支持nvme的linux_Linux nvme驱动初探

本篇研究的nvme驱动基于Linux 3.10.73 ,为什么选择这个版本呢,因为这个版本之后Linux 块层马上就换成支持多队列(可以参考Linux块层多队列之引入内核),小编的SUSE 11.3也正好能编译这个相对比较低的版本。(随后再看最新版本内核上nvme驱动的实现)

通过nvme_alloc_ns可知,nvme设备通过nvme_make_request()函数进入快层:

nvme_alloc_ns()blk_queue_make_request(ns->queue, nvme_make_request);

快速看一下nvme_make_request()这个函数,就会发现nvme设备有多么任性,都没有申请request, 合并bio这种常规操作(因为它支持随机写,而且速度快,不需要),直接把提交过来的bio送到块设备驱动进行处理。(小编第一次看到这个函数时就小激动了一把)。

714 static void nvme_make_request(struct request_queue *q, struct bio *bio)715 {716 struct nvme_ns *ns = q->queuedata;717 struct nvme_queue *nvmeq = get_nvmeq(ns->dev);718 int result = -EBUSY;719720 spin_lock_irq(&nvmeq->q_lock);721 if (bio_list_empty(&nvmeq->sq_cong))722 result = nvme_submit_bio_queue(nvmeq, ns, bio);723 if (unlikely(result)) {724 if (bio_list_empty(&nvmeq->sq_cong))725 add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait);726 bio_list_add(&nvmeq->sq_cong, bio);727 }728729 spin_unlock_irq(&nvmeq->q_lock);730 put_nvmeq(nvmeq);731 }

虽说在这个linux版本上块设备层只支持单队列,但是nvme设备有自己的多队列,每个cpu上绑着一个队列(自己玩)。

每个队列是一个先进先出的FIFO管道,用于连通主机端(Host)和设备端(Device)。其中从主机端发送到设备端的命令管道称之为发送队列.从设备端发送到主机端的命令完成管道称之为完成队列。对于一个IO请求,在主机端组装完成后,通过发送队列发到设备端,然后在设备中进行处理并把相应的完成结果组装成IO完成请求,最后通过完成队列返还给主机端。

不管是发送队列还是完成队列,都是一段内存,通常位于主机端的DDR空间(申请的DMA内存)里。这段内存划分成若干等长的内存块,每一块用于存储一个定常的消息(nvme的发送消息和完成消息都是定常的)。在使用的时候,对于这个队列,有一个头指针和一个尾指针。当两者相等时,队列是空的。见下图。

随着新的消息加入到队列中来,尾指针不停向前移动。因为内存是定常的,因此指针一旦移动到内存的最后一个存储空间,之后再移动的话需要环回到内存的起始位置。因此内存在使用上实际上当作一个环来循环使用。当尾指针的下一个指针就是头指针的时候,这个队列不能再接收新的消息,即队列已经满了,如下图所示。

随着队列的使用者不断取出消息并修改头指针,队列中的元素不断释放,一直到头指针再次追上尾指针时,队列完全变空。

那么主机端将数据写入队列后,设备端是怎么知道该队列所在的内存已经更新了呢?这就需要利用门铃机制(Doorbell)。每个队列都有一个门铃指针。对于发送队列来说,这个指针表示的是发送队列的尾指针。主机端将数据写入到发送队列后,更新映射到位于设备寄存器空间中的门铃的尾指针。实现在SoC控制器芯片上的尾指针一旦被更新,设备就知道新数据到了。

这里并未涉及到主机端如何知道数据已经取走并且设备已经更新了头指针了。nvme协议并没有采用传统的查询寄存器的方式来让主机获得这个信息,因为这样势必造成CPU与硬件寄存器的交互。对于x86来说,每一次与硬件的交互都会带来性能的损失,因此降低硬件交互尤为重要。NVMe的方案是对于这个发送消息,在当它完成的时候会将完成的结果通过DMA的方式写入到内存中,主机根据每个IO请求及其完成请求中的Command Identifier (CID)字段来匹配相应的发送请求和完成请求。其中完成结果中携带有信息表明最新的该请求所对应的发送队列的当前头指针。

nvme_alloc_queue()nvmeq->cqes = dma_alloc_coherent(dmadev, CQ_SIZE(depth),…nvme_process_cq(){/* 检查dma完成请求中 strcut nvme_completion数组,确定发送队列的head指针 */struct nvme_completion cqe = nvmeq->cqes[head];free_cmdid(nvmeq, cqe.command_id, &fn)}

反过来,当设备端完成一个nvme请求时,也需要通过完成队列来把完成的结果告知主机端,这是通过完成队列来实现的。与发送队列不同,完成队列是通过中断机制告诉接收端(主机CPU)收到了新的完成消息并安排后续处理。同样的,为了确定完成队列里到底有多少是新的完成消息,在每一个完成请求中,有一个标志位phase,这个标志位每次写入的数值都会发生改变,并据此确定每一个完成请求是否是新的完成请求(比如一次完成请求phase为1,第二次完成请求phase值为0,从代码来看phase值初始值为1,说明设备发送给主机端phase的值第一次为1)。通过这种机制,虽然主机端不能一下子确定到底有多少新的完成请求,但是可以逐渐的、一步步完成所有的完成请求,并将完成队列用空。随着主机逐渐从完成队列里取出完成消息,主机会更新位于设备上的完成队列头指针寄存器,告诉设备完成队列的实施状况。

nvme_process_cq()/* 检查dma完成请求中 strcut nvme_completion数组,确定完成* 队列的head ,通过门铃通知设备 db(doorbeel) */head = nvmeq->cq_head;writel(head, nvmeq->q_db + (1 <dev->db_stride));

在最新的nvme1.2A中,每一个NVMeController允许最多65535个IO队列和一个Admin队列。Admin队列在设备初始化之后随即创建,包括一个发送队列和一个完成队列。其他的IO队列则是由Admin队列中发送的控制命令来产生的。nvme规定的IO队列的关系比较灵活,既可以一个发送队列对应一个完成队列,也可以几个发送队列共同对应一个完成队列。在主流的实现中,较多采用了一对一的方式。下图列举了两种方式的示意。

nvme_setup_io_queues()负责初始化队列,它先查询了到底有多少个CPU,然后再调用set_queue_count发命令给设备,让设备按照CPU的个数来设置队列的个数。

nvme_setup_io_queues()set_queue_count(dev, nr_io_queues);nvme_set_features(dev,NVME_FEAT_NUM_QUEUES, q_count, 0,&result);

在set_queue_count中,按照之前传入的CPU数量来设置设备的能力。其中NVME_FEAT_NUM_QUEUES对应于NVMe协议的Number of Queues (Feature Identifier 07h)。当然,根据设备能力不同,如果不巧设备刚好没办法支持这么多队列的话,驱动程序也会做一些取舍,选取设备的能力和CPU数量中较小的值。

参考: 晶格思维微信公众号

--The end--

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/339876.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jvm7 jvm8_JVM PermGen –您在哪里?

jvm7 jvm8这篇文章介绍了JVM内存结构的一些基础知识&#xff0c;并快速窥视了PermGen&#xff0c;以了解自Java SE 8出现以来它已消失的地方。 裸基础 JVM只是系统上运行的另一个进程&#xff0c;魔术始于java命令。 像任何OS进程一样&#xff0c;它需要内存才能运行。 请记住…

2019网络教育计算机统考模拟试题,最新2019年网络远程教育《计算机应用基础》统考模拟题库500题(含答案)...

2019年网络远程教育统考《计算机应用基础》考试题库500题[含答案]一、选择题1&#xff0e;启动ExCEl2003应用程序后自动建立的工作簿文件的文件名为_______。A.工作簿B.工作簿文件C.BookFilE1D.Book12&#xff0e;OutlookExprEss的主要功能是__________。A.创建电子邮件账户B.搜…

C++类与对象(中)第二篇

前言&#xff1a; C语言中使用运算符是对内置类型的数据进行操作&#xff0c;但是在C中有了对象&#xff0c;导致对象无法通过运算符进行运算&#xff0c;故引入了运算符重载即需要重新定义这些运算符&#xff0c;赋予已有运算符新的功能&#xff0c;使它能够用于特定类型执行特…

松下壁挂式新风系统推荐_松下壁挂式新风怎么样 松下壁挂式新风系统优势介绍【详解】...

现在很多的家庭都是会安装 新风系统 的&#xff0c;这样也是可以保证室内的空气质量的。其实市场上的新风系统品牌是比较多的&#xff0c;比如松下等&#xff0c;其质量是比较不错的&#xff0c;那么松下壁挂式新风系统的优势有哪些?我们来看看小编的相关介绍吧。松下壁挂式新…

ETL万岁

提取转换负载是用于从一个数据系统中提取数据并加载到另一个数据系统中的过程。 涉及的数据系统称为源系统和目标系统。 来自源系统的数据形状与目标系统不匹配&#xff0c;因此需要进行一些转换以使其兼容&#xff0c;该过程称为Transformation 。 转换是由map / filter / re…

云计算机内存不足怎么办,网易云音乐提示内存不足,电脑提示内存不足-

在有些时候我们的手机百度云提示内存不足了&#xff0c;这该怎么办呢?那么下面就由学习啦小编来给你们说说手机百度云提示内存不足的解决方法吧&#xff0c;希望可以帮到你们哦!手机百度云提示内存不足的解决方法一&#xff1a;手机用久了&#xff0c;需要安装杀毒软件&#x…

黑盒攻击的分类_「图像分类」图像分类中的对抗攻击是怎么回事?

欢迎大家来到图像分类专栏&#xff0c;深度学习分类模型虽然性能强大&#xff0c;但是也常常会因为受到小的干扰而性能崩溃&#xff0c;对抗攻击就是专门研究如何提高网络模型鲁棒性的方法&#xff0c;本文简要介绍相关内容。作者 | 郭冰洋编辑 | 言有三1 简介对于人类而言&…

getter/setter_Getters / Setters。 邪恶。 期。

getter/setter从2003年开始&#xff0c;艾伦霍鲁布&#xff08;Allen Holub&#xff09;讨论了为什么吸气和塞特方法是邪恶的著名文章&#xff0c;关于吸气/塞特方法是否是反模式&#xff0c;应该避免使用&#xff0c;还是我们在面向对象中不可避免地需要它&#xff0c;这是一个…

flowable画图教程_JeeGit企业级快速开发平台-JeeSite4 Flowable入门教程

注&#xff1a; 998元以下课程无咨询服务该课程包含服务内容&#xff1a;299元含发票在线课程观看权购课后&#xff0c;教学资源联系长春叭姐QQ&#xff1a;3211247533 索要教学内容3.1 第一章 业务流程 BPM、工作流引擎、Flowable、Activiti23.1.1 JeeSite4 Flowable 课程简介…

Java / Spring:如何快速生成整个Swagger记录的CRUD REST API

作为开发人员&#xff0c;我们在日常生活中经常面临的最繁琐的任务之一就是编写良好且易于理解的文档。 无论我们的文档只有几行来解释功能的核心功能&#xff0c;还是表明系统的来龙去脉的成熟文章都没关系。 重要的是&#xff0c;我们试图通过文档传达的信息是准确且可理解的…

计算机中的英语六级作文万能模板,大学英语六级作文万能模板7篇

很多人都觉得六级很难&#xff0c;其实主要是作文不会写&#xff0c;今天我们为大家整理了一些六级作文万能模板&#xff0c;大家可以借鉴一下&#xff0c;相信会对大家的提高有所帮助。大学英语六级作文万能模板1∶ 阐述主题型要求从一句话或一个主题出发&#xff0c;按照提纲…

中的实践 中兴_中兴通讯5G智慧治水业务在千岛湖畔下姜村成功实践

近日&#xff0c;中兴通讯智慧治水业务在千岛湖畔下姜村成功实践。这一业务为实现千岛湖下姜村水域的智能化管理、立体化监控提供了可靠保障&#xff0c;也将浙江电信5G网络、中兴通讯5G端到端解决方案在试商用实践中再推进一步。下姜村曾先后获得“全国创先争优先进基层党组织…

consul宕机配置丢失_简单的配置死机

consul宕机配置丢失编写整个框架的目的是为了处理应用程序的配置。 我更喜欢一种简单的方法。 如果通过配置来表示“ 部署之间可能有所不同的所有内容 ”&#xff0c;那么我们应该尝试使配置保持简单。 在Java中&#xff0c;最简单的选项是不起眼的属性文件。 属性文件的缺点是…

html post前md5加密,post提交及MD5加密

C# POST提交/// /// post 网址提交////// 提交网站/// 参数/// 编码方式///public static string PostWebRequest(string postUrl, string paramData, Encoding dataEncode){string ret string.Empty;try{byte[] byteArray dataEncode.GetBytes(paramData); //转化HttpWebReq…

一加7充电_一加真无线耳机曝光,65W快速充电器获认证

一加8系列发布后&#xff0c;曾有消息显示&#xff0c;一加旗下还有一款被称为一加Z的手机将于今年7月登陆市场。现在&#xff0c;距离传言中提到的发布时间越来越近&#xff0c;也再次有消息提到了这一时间点。不过&#xff0c;这次爆料中的新品并不是手机产品。来自爆料人士 …

从工作中清除代码–使用JUnit 5,Mockito和AssertJ编写可执行规范

可执行规范是可以用作设计规范的测试。 通过启用公共语言&#xff08;在DDD世界中&#xff0c;这也称为无处不在的语言 &#xff09;&#xff0c;它们使技术和业务团队能够进入同一页面。 它们充当代码的未来维护者的文档。 在本文中&#xff0c;我们将看到一种编写自动测试的…

怎么使用starwind部署iscsi_2019 年总结 - 多环境多版本的部署

自己几乎经历了部署演进的所有阶段&#xff0c;手动部署、自动部署&#xff0c;部署到服务器、部署到容器。我们也在不断演进并追赶行业前沿的技术/理念。保守估计今年可以基本追赶到行业前沿的最低水平。工作中经历了部署语言的多样化&#xff0c;部署目标的演化/进化&#xf…

家用计算机注意哪些参数,电脑小白买内存条要注意哪些?主要看哪些参数?这些知识要掌握...

内存条是电脑的核心硬件之一&#xff0c;它的作用主要是为CPU服务的&#xff0c;电脑运行的时候&#xff0c;CPU从硬盘里调用数据通过总线寻址放在内存里&#xff0c;内存相当于缓冲处理区&#xff0c;处理好信息后再回馈给CPU&#xff0c;然后电脑再根据指令运行。内存没有记忆…

java 单元测试技巧_其他一些单元测试技巧

java 单元测试技巧在我以前的文章中&#xff0c;我展示了有关JavaBeans单元测试的一些技巧。 在此博客文章中&#xff0c;我将针对单元测试一些相当常见的Java代码&#xff08;即实用程序类和Log4J日志记录语句&#xff09;提供另外两个提示。 测试实用程序类 如果您的实用程序…

日照职业技术学院计算机怎么样,日照职业技术学院宿舍条件怎么样 住宿环境好不好...

又到了一年一度的新生入学季&#xff0c;今年考上日照职业技术学院的学子们对你们的新学校有没有期待&#xff1f;下文中有途网小编给大家整理了日照职业技术学院的宿舍环境&#xff0c;供参考&#xff01;日照职业技术学院宿舍环境如何大学宿舍是各位同学们在大学期间会陪伴我…