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_dax的函数
  • nd_dax
  • dax_pmem_driver

Was this helpful?

  1. nvdimm初探

nd_dax

nd_dax设备可以在两个地方创建:

  • nd_region_probe

  • nd_pmem_probe

经过测试,在nd_pmem_probe中通过nd_dax_probe()创建的设备才是有真实信息的。而具maintainer说,nd_region_probe中生成的设备是一个用来配置的接口。这个暂时还没有去研究,这里我们只看nd_pmem_probe中通过nd_dax_probe创建的流程。

构造nd_dax的函数

这里我们只看通过nd_dax_probe函数创建的流程。

nd_dax_probe()
  nd_dax_alloc()
  nd_pfn_devinit()
  nd_pfn_validate()
  __nd_device_register()

主要就是做了点分配、初始化、检测的任务。

其中想要着重突出的是,如果nd_dax_probe()返回0,也就是一切正常的话。那么它的父函数就会报错,而导致驱动对namespace的probe失败。

这也是为什么我们在sysfs上看不到在这种情况下namespace的驱动的原因。

nd_dax

    nd_dax
    +-------------------------------------------------+  
    |nd_pfn                                           |
    |     (struct nd_pfn)                             |
    |     +-------------------------------------------+
    |     |ndns                                       | points to the ns
    |     |    (struct nd_namespace_common*)          |
    |     |dev                                        |
    |     |    (struct device)                        |
    |     |    +--------------------------------------+
    |     |    |name                                  | "dax0.0"
    |     |    |groups                                | nd_dax_attribute_groups
    |     |    |type                                  | nd_dax_device_type
    |     |    |                                      |
    |     |    |driver_data                           | = dax_region
    |     |    |                                      |
    |     |    +--------------------------------------+
    |     |id                                         |
    |     |    (int)                                  |
    |     |uuid                                       |
    |     |    (u8*)                                  |
    |     |mode                                       | PFN_MODE_NONE
    |     |    (enum nd_pfn_mode)                     |
    |     |align                                      | HPAGE_PMD_SIZE / PAGE_SIZE
    |     |npfns                                      | tricky?
    |     |pfn_sb                                     | setup in nd_pfn_init
    |     |    (struct nd_pfn_sb*)                    |
    |     |    +--------------------------------------+
    |     |    |signature[PFN_SIG_LEN]                |
    |     |    |uuid[16]                              | = nd_pfn->uuid
    |     |    |parent_uuid[16]                       |
    |     |    |   (u8)                               |
    |     |    |mode                                  | = nd_pfn->mode
    |     |    |align                                 | = nd_pfn->align
    |     |    |   (__le32)                           |
    |     |    |                                      |
    |     |    |start_pad                             | trim_pfn_device()
    |     |    |end_trunc                             |
    |     |    |   (__le32)                           |
    |     |    |dataoff                               | meta data
    |     |    |npfns                                 | number of pfn
    |     |    |   (__le64)                           |
    |     |    |                                      |
    +-----+----+--------------------------------------+  

东西有点长,重要的成员加了备注解释其作用。然后再着重解释两个东西:

  • pfn_sb: pfn superblock

  • pfn_sb: start_pad, end_trunc, dataoff

pfn_sb这个结构的内容将要写回到硬件,作为硬件的配置。这样就说通了作为硬件是如何知道某个内存地址的访问是在硬件的什么位置。

然后还有这么几个长得很奇怪的大兄弟是干什么的呢?且看下面这张图。

      |< start_pad >|<    dataoff      >|              |< end_trunc >|
      v             v 8k |page |dax_res v              v             v
      |--------------------------------------------------------------|
      ^                                                              ^
      |                                                              |
  nsio->res.start                                               nsio->res.end

这个nsio就是nd_pfn->ndns指向的nd_namespace_io。而这个的res也就是当前namespace所映射的空间范围。

  • start_pad, end_trunc就是为了对其128M,并不和邻居冲突做的调整

  • dataoff是一段用来存放page结构体和其他buffer的空间

好了,这样是不是觉得清楚点了?

dax_pmem_driver

有了新的设备nd_dax,那么就有对应的驱动来干活。而它的驱动就是dax_pmem_driver。

主要做了这么几件事情:

  • 创建并设置了pfn_sb,并写入硬件

  • 将设备中的空间hotplug到系统内存中

  • 创建了一个dax字符设备,其ops为dax_fops

其中第二件事已经超出了本章节的描述范围,如果有机会将会在内存相关的章节中描述。

而第三件事虽然也可以单独开章节讨论,不过鉴于和本章内容强相关,所以将在下一篇中详细讨论。

Previousnd_namespace_XNextdev_dax

Last updated 3 years ago

Was this helpful?