Kernel Exploring
  • 前言
  • 支持
  • 老司机带你探索内核编译系统
    • 编译出你的第一个内核
    • 内核编译中的小目标
    • 可能是kbuild中最直接的小目标 – help
    • 使用了一个kbuild函数的目标 – cscope
    • 内核中单个.o文件的编译过程
    • 根目录vmlinux的编译过程
    • 启动镜像bzImage的前世今生
    • setup.bin的诞生记
    • 真假vmlinux–由vmlinux.bin揭开的秘密
    • bzImage的全貌
    • kbuild系统浅析
  • 启动时的小秘密
    • INIT_CALLS的秘密
    • 内核参数
  • 内核加载全流程
    • bootloader如何加载bzImage
    • 内核压缩与解压
    • 内核加载的几个阶段
    • 保护模式内核代码赏析
  • 内存管理
    • 内核页表成长记
      • 未解压时的内核页表
      • 内核早期的页表
      • cleanup_highmap之后的页表
      • 映射完整物理地址
      • 启用init_level4_pgt
    • 自底而上话内存
      • e820从硬件获取内存分布
      • 原始内存分配器--memblock
      • 页分配器
        • 寻找页结构体的位置
        • 眼花的页结构体
        • Node-Zone-Page
        • 传说的伙伴系统
        • Compound Page
        • GFP的功效
        • 页分配器的用户们
      • slub分配器
        • slub的理念
        • 图解slub
      • 内存管理的不同粒度
      • 挑战和进化
        • 扩展性的设计和实现
        • 减少竞争 per_cpu_pageset
        • 海量内存
        • 延迟初始化
        • 内存热插拔
        • 连续内存分配器
    • 虚拟内存空间
      • 页表和缺页中断
      • 虚拟地址空间的管家--vma
      • 匿名反向映射的前世今生
      • 图解匿名反向映射
      • THP和mapcount之间的恩恩怨怨
      • 透明大页的玄机
      • NUMA策略
      • numa balance
      • 老版vma
    • 内存的回收再利用
      • 水线
      • Big Picture
      • 手动触发回收
      • Page Fram Reclaim Algorithm
      • swapfile原理使用和演进
    • 内存隔离
      • memcg初始化
      • 限制memcg大小
      • 对memcg记账
    • 通用
      • 常用全局变量
      • 常用转换
    • 测试
      • 功能测试
      • 性能测试
  • 中断和异常
    • 从IDT开始
    • 中断?异常?有什么区别
    • 系统调用的实现
    • 异常向量表的设置
    • 中断向量和中断函数
    • APIC
    • 时钟中断
    • 软中断
    • 中断、软中断、抢占和多处理器
  • 设备模型
    • 总线
    • 驱动
    • 设备
    • 绑定
  • nvdimm初探
    • 使用手册
    • 上帝视角
    • nvdimm_bus
    • nvdimm
    • nd_region
    • nd_namespace_X
    • nd_dax
      • dev_dax
  • KVM
    • 内存虚拟化
      • Qemu内存模型
      • KVM内存管理
  • cgroup
    • 使用cgroup控制进程cpu和内存
    • cgroup文件系统
    • cgroup层次结构
    • cgroup和进程的关联
    • cgroup数据统计
  • 同步机制
    • 内存屏障
    • RCU
  • Trace/Profie/Debug
    • ftrace的使用
    • 探秘ftrace
    • 内核热补丁的黑科技
    • eBPF初探
    • TraceEvent
    • Drgn
  • 内核中的数据结构
    • 双链表
    • 优先级队列
    • 哈希表
    • xarray
    • B树
    • Maple Tree
    • Interval Tree
  • Tools
  • Good To Read
    • 内核自带文档
    • 内存相关
    • 下载社区邮件
Powered by GitBook
On this page
  • 构造nd_region的函数
  • 相关的数据结构
  • acpi_nfit_desc
  • nd_region_desc
  • nd_region
  • nd_region_driver

Was this helpful?

  1. nvdimm初探

nd_region

接着我们来看nd_region这个数据结构。

构造nd_region的函数

老规矩,先看看构造这个数据结构的函数样子。

acpi_nfit_register_regions()
  list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
    rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
      struct nd_region_desc *ndr_desc;
      nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus, ndr_desc);
  }

这是一个非常简略的构建流程,有几点含义想要表达:

  • nd_region的创建由一个acpi_desc->spa触发,并最后挂在spa上

  • 构造的过程中由一个中间变量ndr_desc,由它构造了最后的nd_region

相关的数据结构

这次的牵扯到的数据结构比较多了。

acpi_nfit_desc

    acpi_nfit_desc
    +-----------------------------------------------+
    |dev                                            | = point to an acpi_device
    |    (struct device*)                           |
    +-----------------------------------------------+
    |acpi_header                                    |
    |    (struct acpi_table_header)                 |
    +-----------------------------------------------+
    |spas                                           |  a list of nfit_spa
    |    (struct list_head)                         |  added from acpi_table
    |    +------------------------------------------+  
    |    |nd_region                                 |  *  created from nfit_spa
    |    |    (struct nd_region*)                   |
    |    |ars_state                                 |
    |    |    (unsigned long)                       |
    |    |spa[0]                                    |  looks just have one spa
    |    |    (struct acpi_nfit_system_address)     |
    |    |    +-------------------------------------+
    |    |    |header                               |
    |    |    |    (struct acpi_nfit_header)        |
    |    |    |range_guid[16]                       |
    |    |    |    (u8)                             |
    |    |    |range_index                          |
    |    |    |flags                                |
    |    |    |address                              |  spa address
    |    |    |length                               |
    |    |    |    (u16)                            |
    |    |    |                                     |
    |    +----+-------------------------------------+
    +-----------------------------------------------+

首先来看一下acpi_nfit_desc。其中有一个叫spas的链表。这个的数据在前期从acpi中读取并解析后保存在此。而其中的信息就是构造nd_region的基础。

nd_region_desc

这个结构就是用来构造nd_region的描述结构。在nvdimm驱动中已经是第二次看到这种描述结构了,看来驱动的作者挺喜欢这种方式。

其中在mapping字段可以看出当前nd_region和nvdimm之间的一个关联。

    nd_region_desc
    +-----------------------------------------------+
    |res                                            |
    |     (struct resource*)                        |
    |     +-----------------------------------------+
    |     |name                                     |
    |     |start                                    |  nfit_spa->address
    |     |end                                      |  nfit_spa->address + nfit_spa->length - 1
    +-----+-----------------------------------------+
    |provider_data                                  |  = nfit_spa
    |     (void*)                                   |
    |attr_groups                                    |  = acpi_nfit_region_attribute_groups
    |     (struct attribute_group**)                |
    |num_lanes                                      |
    |numa_node                                      |
    |     (int)                                     |
    |flags                                          |
    |     (unsigned logn)                           |
    |                                               |
    |                                               |
    +-----------------------------------------------+
    |num_mappings                                   |
    |     (u16)                                     |
    |mapping                                        |  created from acpi_nfit_desc->memdev
    |     (struct nd_mapping_desc*)                 |
    |     +-----------------------------------------+
    |     |nvdimm                                   |
    |     |    (struct nvdimm*)                     |
    |     |start/size                               |
    |     |    (u64)                                |
    |     |position                                 |
    |     |    (int)                                |
    +-----+-----------------------------------------+
    |nd_set                                         |  * will be used in nd_region
    |     (struct nd_interleave_set*)               |
    |     +-----------------------------------------+
    |     |cookie1                                  |
    |     |cookie2                                  |
    |     |altcookie                                |
    |     |    (u64)                                |
    |     |type_guid                                |
    |     |    (guid_t)                             |
    +-----+-----------------------------------------+

nd_region

最后就是nd_region这个结构本身了。其中大部分的数据是从刚才的 nd_region_desc 中拷贝过来的。

不过有意思的是,这个nd_region_desc之后就消失了,没有人会记得曾经还有个这么重要的角色。

    nd_region
    +-------------------------------------------------+  
    |dev                                              |
    |   (struct device)                               |
    |   +---------------------------------------------+
    |   |groups                                       | = acpi_nfit_region_attribute_groups
    |   |    (struct attr_groups**)                   |
    |   |                                             |
    |   +---------------------------------------------+
    |   |type                                         | = &nd_pmem_device_type
    |   |    (struct device_type*)                    |   &nd_blk_device_type
    |   |                                             |   &nd_volatile_device_type
    |   |driver_data                                  | = nd_region_data
    |   |    (void*) nd_region_data                   |
    |   |    +----------------------------------------+
    |   |    |ns_count                                |
    |   |    |ns_active                               |
    |   |    |    (int)                               |
    |   |    |hints_shift                             |
    |   |    |    (unsigned int)                      |
    |   |    |flush_wpq[0]                            |
    |   |    |    (void*)                             |
    +---+----+----------------------------------------+  
    |ns_ida                                           |
    |btt_ida                                          |
    |pfn_ida                                          |
    |dax_ida                                          |
    |     (struct ida)                                |
    +-------------------------------------------------+  
    |ns_seed                                          |
    |btt_seed                                         |
    |pfn_seed                                         |
    |dax_seed                                         |
    |     (struct device*)                            |
    +-------------------------------------------------+  
    |lane                                             |
    |     (struct nd_percpu_lan)                      |
    +-------------------------------------------------+  
    |provider_data                                    | = ndr_desc->provider_data
    |     (void *)                                    |
    |ndr_mappings                                     | = ndr_desc->num_mappings
    |     (u16)                                       |
    |ndr_start                                        | = ndr_desc->res->start
    |ndr_size                                         | = ndr_desc->res:size
    |     (u16/u64)                                   |
    |num_lanes                                        | = ndr_desc->num_lanes
    |numa_node                                        | = ndr_desc->numa_node
    |     (int)                                       |
    |                                                 |
    |nd_set                                           | = ndr_desc->nd_set
    |     (struct nd_interleave_set*)                 |
    |                                                 |
    +-------------------------------------------------+  
    |mapping[0]                                       | copied from ndr_des->mapping
    |     (struct nd_mapping)                         |
    |     +-------------------------------------------+
    |     |start/size/position                        |
    |     |    (u64/int)                              |
    |     |labels                                     | a list of
    |     |    (struct list_head)                     | nd_namespace_label
    |     |    +--------------------------------------+
    |     |    |     uuid[NSLABEL_UUID_LEN]           |
    |     |    |     name[NSLABEL_NAME_LEN]           |
    |     |    |     flags                            |
    |     |    |     nlabel                           |
    |     |    |     position                         |
    |     |    |     dpa                              |
    |     |    |                                      |
    |     |    |                                      |
    |     |    +--------------------------------------+
    |     |nvdimm                                     |
    |     |    (struct nvdimm*)                       |
    |     |ndd                                        | = nvdimm->dev->driver_data
    |     |    (struct nvdimm_drvdata*)               |
    |     |                                           |
    |     |                                           |
    +-----+-------------------------------------------+  

补充一点,nd_regioin一共有三种类型:

  • nd_pmem

  • nd_volatile

  • nd_blk

这个类型的区分由dev->type的值来区分,对应上面三种类型各自的type值为:

  • nd_pmem_device_type

  • nd_volatile_device_type

  • nd_blk_device_type

到这里基本算可以结束了,但是我还想再往回推一层。那就是这个type的值是谁来决定的。

在本节的开头我们也看到了,每个nd_region是在acpi_nfit_desc->spa的基础上创建的。而在代码中也正好印证了这一点。nd_region->type也是基于spa的类型决定的。

int nfit_spa_type(struct acpi_nfit_system_address *spa)
{
	int i;

	for (i = 0; i < NFIT_UUID_MAX; i++)
		if (guid_equal(to_nfit_uuid(i), (guid_t *)&spa->range_guid))
			return i;
	return -1;
}

这个函数将spa->range_guid和一个表比较,从而得出当前spa的类型,也就是nd_region的类型了。

nd_region_driver

当一个nd_region构造好了之后,其对应的驱动就该登场干活了。这次就是nd_region_driver,而且还干了不少活。

nd_region_probe()
  nd_region_activate()
  nd_blk_region_init()
  nd_region_register_namespaces()
  nd_region->btt_seed = nd_btt_create(nd_region);
  nd_region->pfn_seed = nd_pfn_create(nd_region);
  nd_region->dax_seed = nd_dax_create(nd_region);

其做了一些初始化的工作后又做了几件重要的事:

  • 创建namespace

  • 创建btt/pfn/dax设备

接下来我们就分步骤看看这几个重要的设备的创建过程。

PreviousnvdimmNextnd_namespace_X

Last updated 3 years ago

Was this helpful?