这篇文章紧接上回分解,在nvme_probe函数的最后一步调用nvme_reset_work进行reset操作,nvme_reset_work的主要工作可以概括如下几个步骤:

  1. 进入nvme_reset_work函数后先检查NVME_CTRL_RESETTING标志,来确保nvme_reset_work不会被重复进入。

  2. 调用nvme_pci_enable

  3. 调用nvme_configure_admin_queue

  4. 调用nvme_init_queue

  5. 调用nvme_alloc_admin_tags

  6. 调用nvme_init_identify

  7. 调用nvme_setup_io_queues

  8. 调用nvme_start_queues/nvme_dev_add之后,接着调用nvme_queue_scan

上篇文章中,我们解析了nvme_configure_admin_queue的内容,本文我们接着介绍nvme_reset_work中的其他函数。

1. 先来看看nvme_init_queue:

static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid)

{

struct nvme_dev *dev = nvmeq->dev;

spin_lock_irq(&nvmeq->q_lock);

nvmeq->sq_tail = 0;

nvmeq->cq_head = 0;

nvmeq->cq_phase = 1;

nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride];

memset((void *)nvmeq->cqes, 0, CQ_SIZE(nvmeq->q_depth));

dev->online_queues++;

spin_unlock_irq(&nvmeq->q_lock);

}

nvme_init_queue做的事情比较简单,就是对之前nvme_configure_admin_queue函数中申请的queue进行初始化操作。在这个过程中,对SQ Tail, CQ Head以及CQ phase变量进行初始化赋值,然后通过q_db指向Doorbell寄存器。

有关SQ、CQ、Phase、Doorbell的详细解释请参考:

NVMe系列专题之二:队列(Queue)管理

2. 看完nvme_init_queue, 我们再接着瞅瞅nvme_alloc_admin_tags:

static int nvme_alloc_admin_tags(struct nvme_dev *dev)

{

if (!dev->ctrl.admin_q) {

dev->admin_tagset.ops = &nvme_mq_admin_ops;

dev->admin_tagset.nr_hw_queues = 1;

dev->admin_tagset.queue_depth = NVME_AQ_BLKMQ_DEPTH - 1;

dev->admin_tagset.timeout = ADMIN_TIMEOUT;

dev->admin_tagset.numa_node = dev_to_node(dev->dev);

dev->admin_tagset.cmd_size = nvme_cmd_size(dev);

dev->admin_tagset.driver_data = dev;

if (blk_mq_alloc_tag_set(&dev->admin_tagset))

return -ENOMEM;

dev->ctrl.admin_q = blk_mq_init_queue(&dev->admin_tagset);

if (IS_ERR(dev->ctrl.admin_q)) {

blk_mq_free_tag_set(&dev->admin_tagset);

return -ENOMEM;

}

if (!blk_get_queue(dev->ctrl.admin_q)) {

nvme_dev_remove_admin(dev);

dev->ctrl.admin_q = NULL;

return -ENODEV;

}

} else

blk_mq_start_stopped_hw_queues(dev->ctrl.admin_q, true);

return 0;

}

这个函数是NVMe设备采用Multi-Queue(MQ)的核心函数,所以在展开解析这个函数之前,我们先聊聊Linux Multi-Queue Block Layer.

如之前NVME文章(NVMe系列专题之二:队列(Queue)管理)中介绍,多队列、原生异步、无锁是NVMe的最大特色,这些为高性能而生的设计迫使Linux Kernel在3.19抛弃了老的单队列Block Layer而转向Multi-Queue Block Layer. 这个Multi-Queue Block Layer的架构直接对应于NVMe的多队列设计,如下图:

所谓的Multi-Queue机制就是在多核CPU的情况下,将不同的block层提交队列分配到不同的CPU核上,以更好的平衡IO的工作负载,大幅提高SSD等存储设备的IO效率。Multi-Queue Block Layer长啥样子呢?画了个图,看一下:

  • Multi-Queue Block Layer分为两层,Software Queues和Hardware Dispatch Queues.

  • Softeware Queues是per core的,Queue的数目与协议有关系,比如NVMe协议,可以有最多64K对 IO SQ/CQ。Software Queues层做的事情如上图标识部分。

  • Hardware Queues数目由底层设备驱动决定,可以1个或者多个。最大支持数目一般会与MSI-X中断最大数目一样,支持2K。设备驱动通过map_queue维护Software Queues和Hardware Queues之间的对接关系。

  • 需要强调一点,Hardware Queues与Software Queues的数目不一定相等,上图1:1 Mapping的情况属于最理想的情况。

到这里,Multi-Queue Block Layer基本理论我们就算回顾完毕了,我回过头来在看看nvme_alloc_admin_tags这个函数。

从上面的代码来看,主要分为三步:

  • 对admin_tagset结构体初始化,在这个过程中特别提一下ops的赋值(后续会用到)。

    static struct blk_mq_ops nvme_mq_admin_ops = {

    .queue_rq = nvme_queue_rq,

    .complete = nvme_complete_rq,

    .init_hctx = nvme_admin_init_hctx,

    .exit_hctx      = nvme_admin_exit_hctx,

    .init_request = nvme_admin_init_request,

    .timeout = nvme_timeout,

    };

  • 接着调用blk_mq_alloc_tag_set分配tag set并与request queue关联,

  • 然后调用blk_mq_init_allocated_queue对hardware queue和software queues进行初始化,并配置两者之间的mapping关系,最后将返回值传递给dev->ctrl.admin_q。

blk_mq_init_allocated_queue调用blk_mq_realloc_hw_ctxs,然调用blk_mq_init_hctx,最后调用set->ops->init_hctx,也就是nvme_admin_init_hctx。

也就是说,blk_mq_init_allocated_queue初始化最终调用的是nvme_admin_init_hctx

static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,

unsigned int hctx_idx)

{

struct nvme_dev *dev = data;

struct nvme_queue *nvmeq = dev->queues[0];

WARN_ON(hctx_idx != 0);

WARN_ON(dev->admin_tagset.tags[0] != hctx->tags);

WARN_ON(nvmeq->tags);

hctx->driver_data = nvmeq;

nvmeq->tags = &dev->admin_tagset.tags[0];

return 0;

}

从上面的code,可以发现,Hardware Queue初始化时,会将nvme_configure_admin_queue函数中申请的NVMe Queue(nvmeq)赋值给Hardware Queue的driver_data. 由此可知,NVMe Queue与Hardware Queue是一一对应的关系,这也是NVMe与Linux Multi-Queue Block Layer默契配合的关键之处。

Linux NVMe Driver学习笔记之6:Admin Queue与Blk-mq初始化相关推荐

  1. Linux NVMe Driver学习笔记之5:Admin SQ/CQ的创建

    这篇文章紧接上回分解,在nvme_probe函数的最后一步调用nvme_reset_work进行reset操作,nvme_reset_work的主要工作可以概括如下几个步骤: 进入nvme_reset ...

  2. Linux NVMe Driver学习笔记之8:IO SQ/CQ的创建过程

    这篇文章紧接上回分解,在nvme_probe函数的最后一步调用nvme_reset_work进行reset操作,nvme_reset_work的主要工作可以概括如下几个步骤: 进入nvme_reset ...

  3. Linux NVMe Driver学习笔记之2:初始化

    上回,我们学习了Linux NVMe驱动的架构以及nvme_core_init的相关内容(),本文我们主要学习一下Linux NVMe驱动初始化过程中都做了哪些事情. 打开Pci.c找到初始化入口mo ...

  4. 网络存储 linux 访问,Linux基础教程学习笔记28——使用Samba访问网络存储

    Linux基础教程学习笔记28--使用Samba访问网络存储 SMB用于Windows和类Linux系统直接的文件共享 安装samba client包: [root@linuxidc~]# yum i ...

  5. KALI LINUX渗透测试学习笔记

    KALI LINUX渗透测试学习笔记 (苑房弘主讲) 第1章 课程介绍 任务1:Kali Linux渗透测试介绍.exe 安全问题的根源: 分层思想 只求功能实现 最大的威胁是人 渗透测试: 尝试挫败 ...

  6. kali linux 渗透测试学习笔记——被动信息收集

    kali linux 渗透测试学习笔记--linux 被动信息收集 被动信息收集 被动信息收集 公开渠道可获得的信息 已公开的信息,通过互联网等渠道去获得 与目标系统不产生直接交互 不对目标访问,扫描 ...

  7. Linux第二周学习笔记(7)

    Linux第二周学习笔记(7) 2.13 文档查看cat_more_less_head_tail (1). cat命令 cat命令:用于查看一个文件的内容并将其显示在屏幕上 cat-A命令:显示所有的 ...

  8. Linux第二周学习笔记(11)

    Linux第二周学习笔记(11) 2.17 隐藏权限lsattr_chattr chattr命令:是设置吟唱隐藏权限的命令,更改Linux文件系统上的文件属性. 参数说明: A:表示文件或目录的ati ...

  9. Linux第二周学习笔记(5)

    Linux第二周学习笔记(5) 2.11.CP命令 cp(copy简写)命令:用来将一个或多个源文件或者目录复制到指定的目的文件或目录. cp –r:复制目录 -i:安全选项 cp命令:拷贝/etc/ ...

  10. Linux进程线程学习笔记:运行新程序

    Linux进程线程学习笔记:运行新程序 周银辉 在上一篇中我们说到,当启动一个新进程以后,新进程会复制父进程的大部份上下文并接着运行父进程中的代码,如果我们使新进程不运行原父进程的代码,转而运行另外一 ...

最新文章

  1. 计算机组成原理读写周期波形图,第3章存储器层次结构-1讲述.ppt
  2. HTTP Header 详解,互联网营销
  3. [Cracking the Coding Interview] 4.4 Check Balanced
  4. (zz)ubuntu 9.04 下无线破解
  5. LeetCode Evaluate Division(并查集)
  6. pyqt5能否用于鸿蒙系统,PyQt显示来自opencv的视频流
  7. mpvue v-html解决方案,mpvue开发小程序所遇问题及h5转化方案
  8. asp.net应用程序级别跟踪
  9. bcp 不能调用where 子句_三、p18-28条件查询、分组聚合、排序where/group by/having/order by...
  10. LM3886-SVO純直流功率放大器
  11. pythonwin下载中文版_Python官方下载 v3.9.0中文版_Win10镜像官网
  12. 操作系统实验·动态分区分配算法
  13. w7文件加密提示没启用服务器,win7文件夹设置密码没有密钥提示该怎么解决
  14. QCC512x QCC302x earbud工程 LED 配置
  15. []575. Distribute Candies
  16. 【Linux】SSH相关命令
  17. 【3d建模】zbrush教程非常适合零基础入门,一学就会
  18. 前端中的三维技术Cesium
  19. 视频号推广小程序是什么;助你快速引流变现;丨国仁网络资讯
  20. 蜘蛛seo超级外链软件

热门文章

  1. OSG加载DEM高程数据
  2. 百度文库源码php,仿百度文库或豆丁网在线浏览doc.pdf.xls.txt源码
  3. tomcat乱码问题
  4. 行业首份社会责任报告诞生,满帮如何写下价值新注脚?
  5. 西门子1200PLC的OB块用法讲解
  6. mapgis67安装输入计算机名称,mapgis67_dogserver67.exe_mapgis67安装教程
  7. 张一鸣在字节跳动7周年庆典上的演讲
  8. 软件项目需求调研报告模板下载_「软件项目管理入门」(21) 需求调研和需求分析怎么做?...
  9. 解决vue+php跨域问题
  10. python实现四阶龙格库塔法