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设备

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

Last updated