# nd\_namespace\_X

在nd\_region的驱动中我们看到其中一个重要的动作就是创建namespace。这个工作交给了nd\_region\_register\_namespaces()函数处理。

## 构造nd\_namespace的函数

先来看看构造namespace的函数流程。

```
nd_region_register_namespaces(struct nd_region *nd_region)
  init_active_labels(struct nd_region *nd_region)
  type = nd_region_to_nstype(nd_region);
  switch (type) {
  case ND_DEVICE_NAMESPACE_IO:
    devs = create_namespace_io(nd_region);
    break;
  case ND_DEVICE_NAMESPACE_PMEM:
  case ND_DEVICE_NAMESPACE_BLK:
    devs = create_namespaces(nd_region);
    break;
  default:
    break;
  }
```

大致看主要做了两件事：

* 配置nd\_regioin->mapping->labels
* 根据nd\_region的NS类型创建对应的namespace

其中labels数据类型看定义就是RFC4122中定义的label了。也算是找到了一个硬件和软件对应的关系。

而create\_namespaces函数的工作则就是扫描nd\_region->mapping->labels来构造的。具体做了什么，让我们来看看相关的数据结构。

## nd\_namespace\_X

在上面的代码片段和nd\_region的章节中我们都可以看出，namespace有三种类型

* nd\_namespace\_blk
* nd\_namespace\_io
* nd\_namespace\_pmem

所以内核中用了三种类型分别表述。我们一个个来看。

### nd\_namespace\_blk

下面是nd\_namespace\_blk这个数据结构的内容。

```
    nd_namespace_blk
    +-------------------------------------------------+  
    |common                                           |
    |    (struct nd_namespace_common)                 |
    |    +--------------------------------------------+
    |    |dev                                         |
    |    |    (struct device)                         |
    |    |    +---------------------------------------+
    |    |    |type                                   | = namespace_blk_device_type
    |    |    |                                       |
    |    |    +---------------------------------------+
    |    |claim                                       |
    |    |    (struct device*)                        |
    |    +--------------------------------------------+  
    |    |force_raw                                   |
    |    |    (int)                                   |
    |    +--------------------------------------------+  
    |    |rw_bytes                                    |
    |    |    ()                                      |
    |    +--------------------------------------------+  
    |    |claim_class                                 | = BTT/BTT2/PFN/DAX
    |    |    (enum nvdimm_claim_class)               |
    +----+--------------------------------------------+  
    |alt_name                                         | = nd_label->name
    |    (char *)                                     |
    |uuid                                             | = nd_label->uuid
    |    (u8*)                                        |
    +-------------------------------------------------+  
    |id                                               |
    |    (int)                                        |
    |lbasize                                          |
    |    (unsigned long)                              |
    |size                                             |
    |    (resource_size_t)                            |
    +-------------------------------------------------+  
    |num_resources                                    |
    |    (int)                                        |
    |res                                              | dpa res array
    |    (struct resource**)                          |
    +-------------------------------------------------+  
```

创建的时候根据nd\_label的信息填写了uuid, alt\_name以及dpa resource数组。

### nd\_namespace\_io

下面是nd\_namespace\_io的数据结构。

```
    nd_namespace_io
    +-------------------------------------------------+  
    |common                                           |
    |    (struct nd_namespace_common)                 |
    |    +--------------------------------------------+
    |    |dev                                         |
    |    |    (struct device)                         |
    |    |    +---------------------------------------+
    |    |    |type                                   | = namespace_io_device_type
    |    |    |                                       |
    |    |    +---------------------------------------+
    |    |claim                                       |
    |    |    (struct device*)                        |
    |    +--------------------------------------------+  
    |    |force_raw                                   |
    |    |    (int)                                   |
    |    +--------------------------------------------+  
    |    |rw_bytes                                    |
    |    |    ()                                      |
    |    +--------------------------------------------+  
    |    |claim_class                                 |
    |    |    (enum nvdimm_claim_class)               |
    +----+--------------------------------------------+  
    |size                                             |
    |    (resource_size_t)                            |
    +-------------------------------------------------+  
    |res                                              |
    |    (struct resource)                            |
    |    +--------------------------------------------+
    |    |start                                       | = nd_region->ndr_start
    |    |end                                         | = res->start + nd_region->ndr_size - 1
    |    |                                            |
    +----+--------------------------------------------+  
    |addr                                             |
    |    (void *)                                     |
    +-------------------------------------------------+  
    |bb                                               |
    |    (struct badblock)                            |
    +-------------------------------------------------+  
```

这种namespace比较简单，创建的时候除了设置了type，就是把res设置成了nd\_region中的空间。

### nd\_namespace\_pmem

```
    nd_namespace_pmem
    +-------------------------------------------------+  
    |nsio                                             |
    |    (struct nd_namespace_io)                     |
    +----+--------------------------------------------+
    |    |common                                      |
    |    |    (struct nd_namespace_common)            |
    |    |    +---------------------------------------+
    |    |    |dev                                    |
    |    |    |    (struct device)                    |
    |    |    |    +----------------------------------+
    |    |    |    |type                              | = namespace_pmem_device_type
    |    |    |    |                                  |
    |    |    |    +----------------------------------+
    |    |    |claim                                  |
    |    |    |    (struct device*)                   |
    |    |    +---------------------------------------+  
    |    |    |force_raw                              |
    |    |    |    (int)                              |
    |    |    +---------------------------------------+  
    |    |    |rw_bytes                               |
    |    |    |    ()                                 |
    |    |    +---------------------------------------+  
    |    |    |claim_class                            |
    |    |    |    (enum nvdimm_claim_class)          |
    |    +----+---------------------------------------+  
    |    |size                                        |
    |    |    (resource_size_t)                       |
    |    +--------------------------------------------+  
    |    |res                                         |
    |    |    (struct resource)                       |
    |    |    +---------------------------------------+
    |    |    |flags                                  | = IORESOURCE_MEM
    |    |    |start                                  | = nd_region->ndr_start + dpa/spa offset
    |    |    |end                                    | = start + size - 1
    |    |    |                                       |
    |    +----+---------------------------------------+  
    |    |addr                                        |
    |    |    (void *)                                |
    |    |--------------------------------------------+  
    |    |bb                                          |
    |    |    (struct badblock)                       |
    +----+--------------------------------------------+  
    |alt_name                                         | = nd_label->name
    |    (char *)                                     |
    |lbasize                                          | = nd_label->lbasize
    |    (unsigned long)                              |
    |uuid                                             | = nd_label->uuid
    |    (u8*)                                        |
    +-------------------------------------------------+  
```

pmem最后整合了一个resource。我猜这个res表示的范围就是内存空间的物理地址了？

## nd\_pmem/blk\_driver

以上三个namespace都会生成自己的设备，这样也就都有各自对应的驱动。

* nd\_blk\_driver
* nd\_pmem\_driver

很不好意思，nd\_pmem\_driver包揽了第二三种namespace的驱动，真实能者多劳的典范。

不过这两个驱动都有一个共同点，就是都调用了nvdimm\_namespace\_common\_probe()做初始化。

这个函数其实也没做啥，主要做了两件事：

* 检测空间大小是否合适
* 设置了uuid

经过仔细研读和实验验证，结果发现了几个神奇的事儿。

* nd\_pmem\_driver不仅仅是namespace的驱动，还是btt/pfn设备的驱动。
* nd\_region\_probe()会也建立btt/pfn/dax设备。
* nd\_pmem\_probe也会通过nd\_btt/pfn/dax\_probe建立对应的设备。

关于这个过程的具体细节可以看[lkml](https://lkml.org/lkml/2019/1/18/1026)中的这个讨论，或许可以让逻辑清楚一点。

总之当namespace被配置成这三种类型的某一种时，nd\_pmem\_probe会通过nd\_btt/pfn/dax\_probe去创建某一种类型的设备。并且有意思的是，这种情况下nd\_pmem\_probe会**失败**。这种高端的方法我还是头一次见。

接下来的事情就交给了各自的设备和驱动了。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://richardweiyang-2.gitbook.io/kernel-exploring/00-brief_navigation/05-namespace.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
