Linux Memory Management:The Function and the Implementation of DAX(Direct Access)Mechanism

文章目录

  • Linux Memory Management:The Function and the Implementation of DAX(Direct Access)Mechanism
    • 1. DAX 简述
    • 2. DAX 的原理
      • 2.1. 普通文件路径如何旁路页缓存
      • 2.2. 映射文件路径如何旁路页缓存
        • 2.2.1 调用 mmap 时发生了什么
        • 2.2.2 请求调页时发生了什么
    • 附录 1:术语表
    • 附录 2:DAX 历史沿革

1. DAX 简述

直接访问(Direct Access,DAX) 机制是一种支持用户态软件直接访问存储于持久内存(Persistent Memory,PM) 的文件的机制,用户态软件无需先将文件数据拷贝到页高速缓存(Page Cache)1

上述描述对应到下面这张图(Typical NVDIMM Software Architecture2)中,就是说(File)和(Memory)这两条 IO 路径都能绕过页高速缓存。

  • 其中 File 路径(下称普通文件路径)表示,用户态软件通过标准文件接口(Standard File API)访问持久内存文件系统。
  • 其中 Memory 路径(下称映射文件路径)表示,用户态软件通过映射文件(Memory-mapped File)直接访问 PM。

2. DAX 的原理

以下将结合 Linux v5.8-rc1 中的 XFS 为例进行介绍。

2.1. 普通文件路径如何旁路页缓存

以文件写路径为例,其由 xfs_file_write_iter 提供,该函数部分代码如下所示:

STATIC ssize_t
xfs_file_write_iter(struct kiocb        *iocb,struct iov_iter       *from)
{struct file        *file = iocb->ki_filp;struct address_space  *mapping = file->f_mapping;struct inode     *inode = mapping->host;ssize_t          ret;if (IS_DAX(inode))return xfs_file_dax_write(iocb, from);if (iocb->ki_flags & IOCB_DIRECT) {ret = xfs_file_dio_aio_write(iocb, from);if (ret != -EREMCHG)return ret;}return xfs_file_buffered_aio_write(iocb, from);
}

这段代码在执行写操作的时候,将分别处理三种情况:

  • DAX

    • 在将文件系统挂载到 PM 设备时,若设置 DAX 标识(mount -o dax),则持久内存文件系统将为所有写操作采用该路径;
    • 该路径主要调用 dax_iomap_rw。该函数在通过 dax_direct_access 获取目标物理内存的地址后,通过 dax_copy_from_iter 调用 NVDIMM 驱动直接把数据拷贝到目标物理内存中,并冲洗(Flush)相应缓存行(Cache Line)。
  • DIO(Direct IO):
    • 在打开文件时,若设置直接 IO 标识(O_DIRECT) ,则文件操作将采用该路径;
    • 该路径主要调用 iomap_dio_rw。该函数仍通过传统存储栈(Storage Stack)访问设备,即通过构造 bio,将请求传递到块设备层(Block Device Layer),再由块设备层调用驱动从而访问设备。
  • 正常 IO:
    • 常规的、使用页缓存的 IO 方式。
    • 该路径主要调用 iomap_file_buffered_write。该函数首先通过 pagecache_get_page 获取页缓存(有关页缓存机制的最新设计,可阅读345),接着通过 iomap_read_page_sync 封装 bio,以请求块设备层调用驱动,将设备上的数据读取到页缓存中。在准备好页缓存之后,调用 iov_iter_copy_from_user_atomic 将用户态软件请求写入的数据拷贝到页缓存中。一切完成之后,通过 iomap_set_page_dirty 将页缓存设置为脏页。如此迭代,直至用户所有数据都写入页缓存,最后通过 balance_dirty_pages_ratelimited 酌情使用后台进程将脏页回写到块设备中。

2.2. 映射文件路径如何旁路页缓存

调用 mmap 时,文件系统仅仅在进程的 mm_struct 中注册了一段使用虚拟内存区域(Virtual Memory Area,VMA)描述的虚拟地址。后续当用户态软件首次访问映射文件时,内存管理单元(Memory Managment Unit)发现页表项(Page Table Entry,PTE)为空,于是触发 14 号故障,即页故障(Page Fault),使得操作系统开始执行请求调页(Demand Paging)。此时,由虚拟内存管理器(Virtual Memory Manager)和文件系统共同管理页表,以建立虚拟内存到物理内存之间的映射关系。注意,以上为同步过程,而非异步过程,因为页故障是一个异常(Exception)而非软/硬件中断(Software/Hardware Interrupt)。

2.2.1 调用 mmap 时发生了什么

在执行 mmap 系统调用时,主要执行 do_mmap 中的 mmap_region,其根据用户态软件的请求,返回一个用于描述一段可用进程虚拟地址空间的 VMA,接着通过 call_mmap 执行文件系统注册的 mmap 实现,最后将该段 VMA 之添加在进程的 mm_struct 中。

XFS 中 mmap 由 xfs_file_mmap 实现,其中主要语句就一个:vma->vm_ops = &xfs_file_vm_ops;。它告诉异常处理例程(Exception Handler)应该调用 xfs_file_vm_ops 中相应的函数处理页错误。

2.2.2 请求调页时发生了什么

请求调页主要执行 __xfs_filemap_fault,其代码如下所示:

static vm_fault_t
__xfs_filemap_fault(struct vm_fault     *vmf,enum page_entry_size   pe_size,bool            write_fault)
{struct inode       *inode = file_inode(vmf->vma->vm_file);struct xfs_inode  *ip = XFS_I(inode);vm_fault_t      ret;trace_xfs_filemap_fault(ip, pe_size, write_fault);if (write_fault) {sb_start_pagefault(inode->i_sb);file_update_time(vmf->vma->vm_file);}xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);if (IS_DAX(inode)) {pfn_t pfn;ret = dax_iomap_fault(vmf, pe_size, &pfn, NULL,(write_fault && !vmf->cow_page) ?&xfs_direct_write_iomap_ops :&xfs_read_iomap_ops);if (ret & VM_FAULT_NEEDDSYNC)ret = dax_finish_sync_fault(vmf, pe_size, pfn);} else {if (write_fault)ret = iomap_page_mkwrite(vmf,&xfs_buffered_write_iomap_ops);elseret = filemap_fault(vmf);}xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);if (write_fault)sb_end_pagefault(inode->i_sb);return ret;
}

显然,这段代码有两条分支:

  • DAX
    该路径主要调用 dax_iomap_fault。该函数首先通过 grab_mapping_entry 获取页缓存中的 DAX Exception Entry(详见3),接着通过 xfs_bmbt_to_iomap 准备一个名为 struct iomap 的数据结构。

    struct iomap {u64           addr; /* disk offset of mapping, bytes */loff_t         offset; /* file offset of mapping, bytes */u64          length; /* length of mapping, bytes */u16           type;   /* type of mapping */u16            flags;  /* flags for mapping */struct block_device  *bdev;  /* block device for I/O */struct dax_device *dax_dev; /* dax_dev for dax operations */void          *inline_data;void           *private; /* filesystem private */const struct iomap_page_ops *page_ops;
    };
    

    准备好 struct iomap 之后,通过 dax_iomap_pfn ,结合 struct iomap 所提供的信息,获取目标 PM 页的物理页号(Physical Page Number,pfn)。之后由 dax_insert_entry 将与该页相关联的 DAX Exception Entry 添加到用于维护页缓存的数据结构 XArray 中。最后调用 vmf_insert_mixed_mkwrite 将从 DAX Exception Entry 中缓存的 pfn 填写到对应虚拟页的 PTE 中。

  • 正常请求调页
    该路径主要调用 filemap_fault。该函数首先通过 do_sync_mmap_readahead 试图同步地预读文件数据(预读行为可受 madvise 系统调用的影响,因此也可能完全不读取),接着通过 pagecache_get_page 分配页缓存,再通过 xfs_vm_readpage 将读取块设备数据的请求发送到块设备层,从而将文件数据读取到页缓存中。在将文件数据拷贝到页缓存之后,取决于映射文件的类型(MAP_SHARED、MAP_PRIVATE)执行不同的分支。最后返回的页保存在 vmf->page 中。

    • 当是 MAP_SHARED,主要调用 do_shared_fault 函数,该函数:

      1. 调用 xfs_file_vm_ops 中注册的 xfs_filemap_page_mkwrite,从而调用 iomap_page_create 在 vmf->page 对应的 struct page 的 private 字段中塞进去一个 struct iomap_page。

        /*
        * Structure allocated for each page when block size < PAGE_SIZE to track
        * sub-page uptodate status and I/O completions.
        */
        struct iomap_page {atomic_t     read_count;atomic_t     write_count;spinlock_t      uptodate_lock;DECLARE_BITMAP(uptodate, PAGE_SIZE / 512);
        };
        
      2. 调用 finish_fault,该函数最终通过 alloc_set_pte 将 vmf->page 映射到虚拟页上,为此需要设置 PTE,并设置 Reverse Mapping6 信息以支持空闲页回收。

    • 当是 MAP_PRIVATE,调用 do_cow_fault。该函数首先通过 alloc_page_vma 为 VMA 分配一个页,该页保存在 vmf->cow_page 中。接着通过 copy_user_highpage 将 vmf->page 中的数据拷贝到 vmf->cow_page 中。最后通过 finish_fault 将 vmf->cow_page 映射到虚拟页上。

附录 1:术语表

  • 持久内存(Persistent Memory,PM):指能通过访存指令(区别于系统调用)访问、可按字节寻址的(区别于块)非易失存储器(Non-volatile Memory,NVM)7。其中可按字节寻址(Byte-addressable)表示每个寻址单位对应一个 PM 单元(而非字或块)。
  • 持久内存系统(PM-aware File System):指支持 DAX 机制的文件系统。该词的常见表述也包括「Persistent Memory File System」89、「DAX Enabled File System」2
  • 映射文件(Memory-mapped File):是一段虚内存逐字节对应于一个文件或类文件的资源,使得应用程序处理映射部分如同访问主内存。10进程地址空间由映射文件和匿名内存(Anonymous Memory)组成。

附录 2:DAX 历史沿革

  • 2015,Carsten Otte 在 Linux v2.6 中引入 XIP(Execute-in-place)机制11
    XIP 原本用于嵌入式系统,它摒弃了存储栈中的通用块层及驱动层,并旁路了页高速缓存,使得进程可以直接访问只读存储器或基于 Flash 的内存。
  • 2014 年,Subramanya R Dulloor 等人在 PMFS 中基于 XIP 机制管理 PM12
  • 同年,Matthew Wilcox 改进了 XIP 并提出了名为 DAX 的子系统。
    他在尝试将 XIP 集成到 Ext4 文件系统时,发现 XIP 无法很好地应对竞争条件(Race Conditions)13。当多个线程需要同时访问共享资源,且结果依赖于它们执行的相对速度时,便出现了竞争条件14。他所做出的最主要的变动,就是使用文件系统的 get_block 路径替代 struct address_space_operations 中的 get_xip_mem操作15

  1. Corbet J. The future of DAX. https://lwn.net/Articles/717953/, 2017 ↩︎

  2. intel. NVDIMM  Namespace  Specification. http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf, 2015 ↩︎ ↩︎

  3. Zwisler R. A multi-order radix tree. https://lwn.net/Articles/688130/, 2016 ↩︎ ↩︎

  4. Corbet J. The XArray data structure. https://lwn.net/Articles/745073/, 2018 ↩︎

  5. Corbet J. The future of the page cache. http://tinylab.org/lwn-712467/, 2017 ↩︎

  6. McCracken D. Object-based reverse mapping. in: Proceedings of the Ottawa Linux Symposium (OLS’04). Ottawa, Ontario, Canada: July 21–24, 2004. 357~360 ↩︎

  7. Nalli S, Haria S, Hill M D, et al. An analysis of persistent memory use with WHISPER. in: Proceedings of the Twenty-Second International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS’17). Xi’an, Shanxi, China: ACM, April 8-12, 2017. 135~148 ↩︎

  8. SNIA. NVM Programming Model (NPM) v1.2. https://www.snia.org/sites/default/files/technical_work/final/NVMProgrammingModel_v1.2.pdf, 2017 ↩︎

  9. https://software.intel.com/content/www/us/en/develop/articles/persistent-memory-faq.html ↩︎

  10. https://zh.wikipedia.org/zh-hans/%E5%86%85%E5%AD%98%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6 ↩︎

  11. Corbet J. Execute-in-place. https://lwn.net/Articles/135472/, 2005 ↩︎

  12. Dulloor S R, Kumar S, Keshavamurthy A, et al. System software for persistent memory. in: Proceedings of the Ninth European Conference on Computer Systems (EuroSys’14). ‎‎Amsterdam, North Holland, Netherlands: ACM, April 13-16, 2014. 1~15 ↩︎

  13. Corbet J. Supporting filesystems in persistent memory. https://lwn.net/Articles/610174/, 2014 ↩︎

  14. 孙钟秀, 费翔林, 骆斌. 操作系统教程. 第4版. 北京市: 高等教育出版社, 2008. 1~509 ↩︎

  15. Wilcox M. Add support for NV-DIMMs to ext4. https://lwn.net/Articles/613384/, 2014 ↩︎

Linux 内存管理:DAX(Direct Access)机制的作用及实现原理相关推荐

  1. Linux内存管理:反向映射机制(匿名页,文件页和ksm页)

    目录 1.反向映射的发展 2.反向映射应用场景 3.匿名页的反向映射 4.文件页的反向映射 5.ksm页的反向映射 6.总结 7.作者简介 8.推荐阅读 为了系统的安全性,Linux内核将各个用户进程 ...

  2. Linux内存管理回收机制

    Linux内存管理回收机制 1.Linux内存管理简介     Linux将所管理的内存划分为内存节点(node).内存分区(zone)和页框(page). 1.1.内存节点(node)     依据 ...

  3. linux内存管理简介,Linux内存管理机制简介

    在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,区别于 Windows的内存管理. 主要特点是,无论物理内存有 ...

  4. Linux内存管理机制研究

    Linux内存管理机制研究 查看linux系统中处于free状态的内存有两个角度,一个是从内核的角度来看,一个是从应用层的角度来看的. 1.从内核的角度来看free的内存,就是内核目前可以直接分配到, ...

  5. linux内存管理的主要概念是虚拟内存,有关linux内存管理机制的相关内容,linux物理内存和虚拟内存,深入了解Linux内存运行 ......

    在linux中空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然. 这是Linux内存管理的一个优秀特性,区别于Windows的内存管理. 主要特点: 无论物理内存有多大,L ...

  6. Linux内存管理:内存寻址之分段机制与分页机制

    目录 Linux 内存寻址之分段机制 前言 分段到底是怎么回事? 实模式的诞生(16位处理器及寻址) 保护模式的诞生(32位处理器及寻址) IA32的内存寻址机制 寻址硬件 IA32的三种地址 MMU ...

  7. Linux内存管理:分页机制

    <Linux内存管理:内存描述之内存节点node> <Linux内存管理:内存描述之内存区域zone> <Linux内存管理:内存描述之内存页面page> < ...

  8. linux内存管理机制以及free命令详解

    linux内存管理机制以及free命令详解 一.linux内存管理机制 1.物理内存和虚拟内存 直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存 ...

  9. Linux内存管理机制(最透彻的一篇)

    摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法.力求从外到内.水到渠成地引导网友分析Linux的内存管理与使用.在 ...

  10. 万字整理,图解Linux内存管理所有知识点

    Linux的内存管理可谓是学好Linux的必经之路,也是Linux的关键知识点,有人说打通了内存管理的知识,也就打通了Linux的任督二脉,这一点不夸张.有人问网上有很多Linux内存管理的内容,为什 ...

最新文章

  1. 听说你有病,我这儿可有对症的药
  2. python编程和c语言编程的区别-通过实例浅析Python对比C语言的编程思想差异
  3. 从函数劫持角度看开发调试工具AlloyLever
  4. 历史性胜利!纽约曼哈顿充电站数量超过加油站
  5. JAVA:网络编程总结
  6. python的flask服务器修改,python-Nginx,uWSGI,Flask应用程序直到服务器重启后才会显示更改...
  7. Oracle的主键和外键
  8. 《数据结构》C++代码 堆(优先队列)
  9. 你应该知道的一些 ADB 命令
  10. 【JavaScript】新浪微博批量删除脚本
  11. SQLServer数据库同步准实时解决方案
  12. 第四届“云鼎奖”网络投票火热进行中——入围名单一览
  13. 2.数据类型--数值类型
  14. 使用Qt编辑关闭窗口程序的一些见解
  15. html设置http缓存代码
  16. 阿里云内网和公共NTP服务器(网络时间协议-时间同步服务)
  17. 根据递推公式构造系数矩阵用于快速幂
  18. HTML,JS和CSS实现减肥周期计算(附源码)
  19. 为什么边缘计算会这么受欢迎
  20. 计算机软件图标乱码,win7系统图标汉字显示乱码变成奇怪符号的解决方法

热门文章

  1. 中国农业大学计算机研究生专业课,中国农业大学2019计算机考研纯干货分享
  2. Log4j不同级别输出到不同文件的几种方式
  3. Oracle 查看 SQL执行计划 SQL性能分析
  4. android word缺少字体下载,OfficeSuite字体包
  5. web测试和app测试的区别你知道吗?
  6. BP神经网络预测模型
  7. 9、网友问答----有关清零问题------------------labview宝典
  8. IDEA和MySQL数据库建立连接
  9. 西门子plc编程软件step 7 microwin smart下载指南
  10. 一个离线的简单的 JSON 格式化编辑器