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
  • 构造nvdimm的函数
  • 相应的数据结构
  • nvdimm_driver

Was this helpful?

  1. nvdimm初探

nvdimm

创建了nvdimm_bus,读取了nfit中的信息后,接下来驱动就根据这些信息创建nvdimm这个数据结构了。

这个数据结构就对应着一个物理的dimm,这可能也是为什么使用memmap=内核参数时没有这个设备的原因。

构造nvdimm的函数

这个过程由acpi_nfit_register_dimms()函数完成,大致的流程如下:

list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
    __nvdimm_create();
}

从这个片段能看出nvdimm结构体是从acpi_desc->dimms的信息构建的。

相应的数据结构

看了函数调用,现在来看看对应的数据结构的样子。虽然看了有时候也还是不懂。

    acpi_nfit_desc
    +-----------------------------------------------+
    |dimms                                          |  a list of nfit_mem
    |    (struct list_head)                         |  parsed from above spa & memdevs
    |    +------------------------------------------+
    |    |nvdimm                                    |  *
    |    |     (struct nvdimm*)                     |
    |    |     +------------------------------------+
    |    |     |dev                                 |
    |    |     |   (struct device)                  |
    |    |     |   +--------------------------------+
    |    |     |   |name                            |  = "nmem%d"
    |    |     |   |groups                          |  = acpi_nfit_dimm_attribute_groups
    |    |     |   |                                |
    |    |     |   |driver_data                     |  = struct nvdimm_drvdata
    |    |     |   |   (void*)                      |
    |    |     |   |  +-----------------------------+
    |    |     |   |  |dev                          |
    |    |     |   |  |   (struct device*)          |
    |    |     |   |  |ns_current, ns_next          |
    |    |     |   |  |nslabel_size                 |  = 128
    |    |     |   |  |   (int)                     |
    |    |     |   |  |nsarea                       |
    |    |     |   |  |     (nd_cmd_get_config_size)|
    |    |     |   |  |data                         |  config data
    |    |     |   |  |   (void*)                   |  namespace index + namespace label
    |    |     |   |  |dpa                          |  created from namespace label
    |    |     |   |  |   (struct resource)         |  from nvdimm_drvdata->data
    |    |     |   |  +-----------------------------+
    |    |     |   |                                |
    |    |     |   +--------------------------------+
    |    |     |provider_data                       |  = nfit_mem
    |    |     |   (void*)                          |
    |    |     |flush_wpq                           |
    |    |     |   (struct resource*)               |
    |    |     |dwork                               |
    |    |     |   (struct delayed_work)            |
    |    |     |sec.ops                             |
    |    |     |                                    |
    |    |     |                                    |
    |    +-----+------------------------------------+
    |    |memdev_dcr                                |
    |    |memdev_pmem                               |
    |    |memdev_bdw                                |
    |    |     (struct acpi_nfit_memory_map)        |
    |    |                                          |
    |    +------------------------------------------+
    |                                               |
    +-----------------------------------------------+

在这个数据结构的部分截取中可以看到,acpi_nfit_desc中包含了一个类型为nfit_mem的链表。而函数acpi_nfit_register_dimms就是根据这个链表来构造硬件相对无关的nvdimm数据。

nvdimm_driver

nvdimm对应的是一个物理的dimm,这个设备生成之后就需要去检查并初始化。这个工作由它的驱动nvdimm_driver来完成。

驱动做的关键工作就是根据硬件信息设置这个数据结构中的dev->driver_data。

这个结构是一个nvdimm_drvdata类型,其具体的成员也已经在图中显示。主要解释其中两个内容:

  • data: 驱动将硬件上的namespace index和namespace label_size读取到这段内存

  • dpa: 驱动根据上面的data信息,将dimm对应的dpa信息转换成res树

我猜这些信息会留着后续使用,那就等着看吧。

Previousnvdimm_busNextnd_region

Last updated 3 years ago

Was this helpful?