您的位置:首页 > 运维架构 > Linux

NVMe的Linux内核驱动分析

2020-01-15 12:05 2611 查看

NVMe的Linux驱动是如何实现的。首先NVMe本身是一个块设备,因此NVMe的驱动也是遵循块设备的驱动架构。本文通过两部分介绍NVMe的驱动程序,一部分是操作系统如何创建NVMe块设备,另外一部分是分析一下NVMe的主要流程,包括读写流程和管理流程等。

创建NVMe块设备

对于Linux的块设备来说,其主要的是通过device_add_disk或者add_disk函数(后者是对前者的简单包装)来向操作系统添加一个设备实例。具体原理我们在之前的文章中已经介绍过,本文不再啰嗦了,想了解的同学请自行翻阅一下历史文章。其基本原理就是通过调用该函数,就会创建在/dev目录下看到的类似sdX的块设备。

NVMe本身也是块设备,自然也不会跳出这个大框架。首先从硬件层面上,我们知道任何设备必须通过某个总线与CPU向连接,NVMe则正是通过PCIe总线与CPU相连

 

图1 Linux内核的总线架构

当然,目前NVMe除了可以通过PCIe总线与CPU相连外,还可以通过其它通道连接,比如FC或者IB。后者则是一种将NVMe设备从计算节点独立出来的方式,也就是此时NVMe就不再是一个卡设备,而是一个独立机箱的设备。无论何种方式相连接,其本质是一样等。

然后是操作系统软件层面的内容。硬件的连通性是基础,当硬件已经连通后,就可以在Linux内核层面发现设备,并进行初始化了。软件层面的初始化有两种情况,一种是计算机启动的时候,操作系统会扫描总线上的设备,并完成初始化;另外一种情况是设备在系统启动后连接的,此时需要手动触发扫描的过程。

无论是系统启动也好,还是手动触发扫描也好,NVMe发现设备的核心流程是一样的。

图2 设备初始化主流程

与其它块设备类似,NVMe设备初始化完成后会在/dev目录下出现一个文件。NVMe设备会出现一个形如nvmeXnY的设备文件。如图3所示,红色方框中的为一个NVMe块设备。

图3 Linux中的NVMe块设备

核心实现分析

上面我们简要的介绍了初始化的主流程。在上面初始化流程中需要重点关注的是nvme_alloc_ns函数的流程。该函数完成了块设备创建、基本信息填充和块设备注册到内核等工作。如图4是该函数的部分代码片段。这部分片段完成了函数指针的初始化、命令队列初始化和设备名称的初始化等工作。具体关于nvme_alloc_ns函数源代码的逻辑请自行阅读代码,本文不再赘述。

图4 代码初始化

在整个初始化流程中比较关键的是对请求队列(request_queue)中请求处理函数指针(make_request_fn)的初始化及多队列函数集(mq_ops)的初始化。因为,这里的函数正是NVMe区别于SCSI等类型设备数据处理流程的地方。

NVMe设备的IO流程

为了便于理解NVMe的处理流程,我们给出了传统SCSI及NVMe数据处理的对比流程。如图5所示,整个流程是从通用块层的接口(submit_bio)开始的,这个函数大家都非常清楚了。

图5 NVMe数据流程

对于NVMe设备来说,在初始化的时候初始化函数指针make_request_fn为nvme_queue_rq,该函数就是NVMe驱动程序的请求处理接口。该函数最终会将请求写入NVMe中的SQ队列当中,并通知控制器处理请求。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
站内首发文章 小志1989 发布了38 篇原创文章 · 获赞 3 · 访问量 862 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: