dev_dax

当我们生成了nd_dax设备后,nvdimm驱动的任务就基本结束了。或者应该说,nvdimm驱动最后的任务是创建一个dev_dax设备,由这个设备接过最后的枪。

构造dev_dax的过程

从nd_dax构造dev_dax的过程在dax_pmem_probe中完成。

dax_pmem_probe()
  nvdimm_setup_pfn(nd_pfn, &pgmap);
    nd_pfn_init(nd_pfn);
    __nvdimm_setup_pfn(nd_pfn, pgmap);
  dax_region = alloc_dax_region(dev, region_id, &res,
    le32_to_cpu(pfn_sb->align), addr, PFN_DEV|PFN_MAP);
  dev_dax = __devm_create_dev_dax(dax_region, id, &pgmap, subsys);
    dax_dev = alloc_dax(dev_dax, NULL, NULL);
      dax_dev = dax_dev_get(devt);
        ...
        alloc_inode(super_block)
    dev_dax->dax_dev = dax_dev;

上面的流程就是从nd_dax/nd_pfn设备构造到dev_dax的过程。大致可以分成三个步骤:

  • nvdimm_setup_pfn() 对nd_pfn中的成员做了设置,比如对齐和计算page struct的空间

  • alloc_dax_region() 这是构造dev_dax所需的信息

  • 函数__devm_create_dev_dax用来创建dax_dev,也就是dax文件系统。值得注意的是这个数据结构是通过super_block创建inode时候创建的。

dev_dax是个庞大的结构体,就让我们来看一看吧。

dev_dax, dax_dev, dax_region

    dev_dax
    +-------------------------------------+<----------------------------+
    |id                                   |                             |
    |   (int)                             |                             |
    |dev                                  |                             |
    |   (struct device)                   |                             |
    |   +---------------------------------+                             |
    |   |devt                             |  dax_dev.inode->i_rdev      |
    |   |class                            |  dax_class                  |
    |   |/ bus                            |  dax_bus_type               |
    |   |groups                           |  dax_attribute_groups       |
    |   |parent                           |  dax_region->dev = nd_pfn   |
    |   |                                 |                             |
    |   |kobj->name                       |  = "dax0.0"                 |
    |   +---------------------------------+                             |
    |                                     |                             |
    |dax_dev                              |                             |
    |   (struct dax_device*)              |                             |
    |   +---------------------------------+                             |
    |   |private                      ----| ----------------------------+
    |   |   (void*)                       |
    |   |inode                            |      
    |   |   (struct inode)                |      
    |   |   +-----------------------------+      
    |   |   |i_cdev                   ----|-----+
    |   |   |   (struct cdev*)            |     |
    |   |   +-----------------------------+     |
    |   |cdev                             |<----+
    |   |   (struct cdev)                 |  /dev/dax0.0
    |   |   +-----------------------------+
    |   |   |ops                          |  dax_fops
    |   |   |                             |
    |   |   +-----------------------------+
    |   |                                 |
    |   |host                             |
    |   |   (char*)                       |
    |   |ops                              |
    |   |   (struct dax_operations*)      |
    |   +---------------------------------+
    |                                     |
    |region                               |
    |   (struct dax_region*)              |
    |   +---------------------------------+
    |   |id                               |
    |   |   (int)                         |
    |   |dev                              | = nd_pfn.dev
    |   |   (struct device*)              |
    |   |ida                              |
    |   |   (struct ida)                  |
    |   |res                              |
    |   |   (struct resource)             |
    |   |   +-----------------------------+
    |   |   |start                        | nsio->res.start + start_pad + dataoff
    |   |   |end                          | nsio->res.start + size - end_trunc
    |   |   +-----------------------------+
    |   |                                 |
    +---+---------------------------------+
    |ref                              <---|------------------------------------+
    |     (struct percpu_ref)             |                                    |
    |     +-------------------------------+                                    |
    |     |count                          |                                    |
    |     |  (atomic_long_t)              |                                    |
    |     |percpu_count_ptr               |                                    |
    |     |  (unsigned long)              |                                    |
    |     |release                        | = dev_dax_percpu_release           |
    |     |confirm_switch                 |                                    |
    |     |  (percpu_ref_func_t)          |                                    |
    |     |force_atomit                   |                                    |
    |     |                               |                                    |
    |     |rcu                            |                                    |
    |     |  (struct rcu_head)            |                                    |
    +-----+-------------------------------+                                    |
    |pgmap                                | setup in nvdimm_setup_pfn          |
    |     (struct dev_pagemap)            |                                    |
    |     +-------------------------------+                                    |
    |     |dev                            | = nd_pfn.dev                       |
    |     |   (struct device*)            |                                    |
    |     |ref                            | -----------------------------------+
    |     |   (struct percpu_ref*)        |
    |     |res                            |
    |     |   (struct resource)           |
    |     |   +---------------------------+
    |     |   |start                      |  nsio->res.start + start_pad
    |     |   |end                        |  nsio->res.start + size - end_trunc
    |     |   +---------------------------+
    |     |page_free                      |
    |     |   (dev_page_free_t)           |
    |     |kill                           | = dax_pmem_percpu_kill
    |     |   ()                          |
    |     |                               |
    |     |altmap                         |
    |     |   (struct vmem_altmap)        |
    |     |   +---------------------------+
    |     |   |base_pfn                   | = PFN_SECTION_ALIGN_DOWN(nsio->res.start + start_pad)
    |     |   |reserve                    | = PHYS_PFN(SZ_8K)
    |     |   |   (const unsigned long)   |
    |     |   |free                       | = PHYS_PFN(offset - SZ_8K);
    |     |   |align                      |
    |     |   |alloc                      |
    |     |   |   (unsigned long)         |
    |     |   +---------------------------+
    |     |                               |
    +-----+-------------------------------+

着重讲几点:

  • 最终的目标是生成dev_dax设备,该设备对应一个字符类型的文件/dev/dax0.0

  • /dev/dax0.0的fops是dax_fops,所以后面的mmap就靠它了

  • dev_dax生成的信息在dax_region中

  • dax_region中res就是对齐过后,去掉元数据的部分;

怎么样,这下是不是够爽?

dev_dax的驱动device_dax_driver

既然有了dev_dax,那么这个设备是如何开始它的工作的呢?再来回顾一下dev_dax结构体中新创建的设备。

    dev                                                                 
    (struct device)                                                  
    +---------------------------------+                              
    |devt                             |  dax_dev.inode->i_rdev       
    |class                            |  dax_class                   
    |/ bus                            |  dax_bus_type                
    |groups                           |  dax_attribute_groups        
    |parent                           |  dax_region->dev = nd_pfn    
    |                                 |                              
    |kobj->name                       |  = "dax0.0"                  
    +---------------------------------+                              

这部分已经超出了nvdimm驱动的范畴,但是为了把故事讲完,我们还是要看一下生成的这个设备是如何被使用到的。

因为这个设备是在dax_bus_type总线上的,所以它的驱动也应该是在同一个总线上的了。这个默认的驱动就是device_dax_driver.

static struct dax_device_driver device_dax_driver = {
	.drv = {
		.probe = dev_dax_probe,
		.remove = dev_dax_remove,
	},
	.match_always = 1,
};

探测

这个驱动的探测函数dev_dax_probe主要做了两件事情:

  • devm_memremap_pages(dev, &dev->pgmap)

  • cdev_init(cdev, &dax_fops);

Last updated