dsphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextEnglish}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget /block/blk-mqmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget /translations/zh_TW/block/blk-mqmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget /translations/it_IT/block/blk-mqmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget /translations/ja_JP/block/blk-mqmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget /translations/ko_KR/block/blk-mqmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget /translations/sp_SP/block/blk-mqmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageChinese (Simplified)uh1h hh _documenthsourceNlineNubhcomment)}(h SPDX-License-Identifier: GPL-2.0h]h SPDX-License-Identifier: GPL-2.0}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhhM/var/lib/git/docbuild/linux/Documentation/translations/zh_CN/block/blk-mq.rsthKubhnote)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]h paragraph)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hh5Documentation/translations/zh_CN/disclaimer-zh_CN.rsthKhhubah}(h]h ]h"]h$]h&]uh1hhhhhhhhNubh field_list)}(hhh](hfield)}(hhh](h field_name)}(hOriginalh]hOriginal}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh field_body)}(hDocumentation/block/blk-mq.rst h]h)}(hDocumentation/block/blk-mq.rsth]hDocumentation/block/blk-mq.rst}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(h翻译h]h翻译}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hhhKubh)}(h/柯子杰 kezijie h]h)}(h.柯子杰 kezijie h](h柯子杰 kezijie <}(hj hhhNhNubh reference)}(hkezijie@leap-io-kernel.comh]hkezijie@leap-io-kernel.com}(hj*hhhNhNubah}(h]h ]h"]h$]h&]refuri!mailto:kezijie@leap-io-kernel.comuh1j(hj ubh>}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhj ubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(h校译h]h校译}(hjShhhNhNubah}(h]h ]h"]h$]h&]uh1hhjPhhhKubh)}(hhh]h}(h]h ]h"]h$]h&]uh1hhjPubeh}(h]h ]h"]h$]h&]uh1hhhhK hhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubhsection)}(hhh](htitle)}(h,多队列块设备 I/O 排队机制 (blk-mq)h]h,多队列块设备 I/O 排队机制 (blk-mq)}(hj}hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjxhhhhhKubh)}(hX多队列块设备 I/O 排队机制提供了一组 API,使高速存储设备能够同时在多个队列中 处理并发的 I/O 请求并将其提交到块设备,从而实现极高的每秒输入/输出操作次数 (IOPS),充分发挥现代存储设备的并行能力。h]hX多队列块设备 I/O 排队机制提供了一组 API,使高速存储设备能够同时在多个队列中 处理并发的 I/O 请求并将其提交到块设备,从而实现极高的每秒输入/输出操作次数 (IOPS),充分发挥现代存储设备的并行能力。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjxhhubjw)}(hhh](j|)}(h介绍h]h介绍}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjhhhhhKubjw)}(hhh](j|)}(h背景h]h背景}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjhhhhhKubh)}(hX~磁盘从 Linux 内核开发初期就已成为事实上的标准。块 I/O 子系统的目标是尽可能 为此类设备提供最佳性能,因为它们在进行随机访问时代价极高,性能瓶颈主要在机械 运动部件上,其速度远低于存储栈中其他任何层。其中一个软件优化例子是根据硬盘磁 头当前的位置重新排序读/写请求。h]hX~磁盘从 Linux 内核开发初期就已成为事实上的标准。块 I/O 子系统的目标是尽可能 为此类设备提供最佳性能,因为它们在进行随机访问时代价极高,性能瓶颈主要在机械 运动部件上,其速度远低于存储栈中其他任何层。其中一个软件优化例子是根据硬盘磁 头当前的位置重新排序读/写请求。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hX+然而,随着固态硬盘和非易失性存储的发展,它们没有机械部件,也不存在随机访问代 码,并能够进行高速并行访问,存储栈的瓶颈从存储设备转移到了操作系统。为了充分 利用这些设备设计中的并行性,引入了多队列机制。h]hX+然而,随着固态硬盘和非易失性存储的发展,它们没有机械部件,也不存在随机访问代 码,并能够进行高速并行访问,存储栈的瓶颈从存储设备转移到了操作系统。为了充分 利用这些设备设计中的并行性,引入了多队列机制。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK!hjhhubh)}(hXU原来的设计只有一个队列来存储块设备 I/O 请求,并且只使用一个锁。由于缓存中的 脏数据和多处理器共享单锁的瓶颈,这种设计在 SMP 系统中扩展性不佳。当不同进程 (或同一进程在不同 CPU 上)同时执行块设备 I/O 时,该单队列模型还会出现严重 的拥塞问题。为了解决这些问题,blk-mq API 引入了多个队列,每个队列在本地 CPU 上拥有独立的入口点,从而消除了对全局锁的需求。关于其具体工作机制的更深入说明, 请参见下一节( `工作原理`_ )。h](hX?原来的设计只有一个队列来存储块设备 I/O 请求,并且只使用一个锁。由于缓存中的 脏数据和多处理器共享单锁的瓶颈,这种设计在 SMP 系统中扩展性不佳。当不同进程 (或同一进程在不同 CPU 上)同时执行块设备 I/O 时,该单队列模型还会出现严重 的拥塞问题。为了解决这些问题,blk-mq API 引入了多个队列,每个队列在本地 CPU 上拥有独立的入口点,从而消除了对全局锁的需求。关于其具体工作机制的更深入说明, 请参见下一节( }(hjhhhNhNubj))}(h`工作原理`_h]h 工作原理}(hjhhhNhNubah}(h]h ]h"]h$]h&]name 工作原理refidid3uh1j(hjresolvedKubh )。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK%hjhhubeh}(h]id2ah ]h"]背景ah$]h&]uh1jvhjhhhhhKubjw)}(hhh](j|)}(h 工作原理h]h 工作原理}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjhhhhhK-ubh)}(h当用户空间执行对块设备的 I/O(例如读写文件)时,blk-mq 便会介入:它将存储和 管理发送到块设备的 I/O 请求,充当用户空间(文件系统,如果存在的话)与块设备驱 动之间的中间层。h]h当用户空间执行对块设备的 I/O(例如读写文件)时,blk-mq 便会介入:它将存储和 管理发送到块设备的 I/O 请求,充当用户空间(文件系统,如果存在的话)与块设备驱 动之间的中间层。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK/hjhhubh)}(hXGblk-mq 由两组队列组成:软件暂存队列和硬件派发队列。当请求到达块层时,它会尝 试最短路径:直接发送到硬件队列。然而,有两种情况下可能不会这样做:如果该层有 IO 调度器或者是希望合并请求。在这两种情况下,请求将被发送到软件队列。h]hXGblk-mq 由两组队列组成:软件暂存队列和硬件派发队列。当请求到达块层时,它会尝 试最短路径:直接发送到硬件队列。然而,有两种情况下可能不会这样做:如果该层有 IO 调度器或者是希望合并请求。在这两种情况下,请求将被发送到软件队列。}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK3hjhhubh)}(hXD随后,在软件队列中的请求被处理后,请求会被放置到硬件队列。硬件队列是第二阶段 的队列,硬件可以直接访问并处理这些请求。然而,如果硬件没有足够的资源来接受更 多请求,blk-mq 会将请求放置在临时队列中,待硬件资源充足时再发送。h]hXD随后,在软件队列中的请求被处理后,请求会被放置到硬件队列。硬件队列是第二阶段 的队列,硬件可以直接访问并处理这些请求。然而,如果硬件没有足够的资源来接受更 多请求,blk-mq 会将请求放置在临时队列中,待硬件资源充足时再发送。}(hj1hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK7hjhhubjw)}(hhh](j|)}(h软件暂存队列h]h软件暂存队列}(hjBhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj?hhhhhKhj?hhubh)}(hX>暂存队列可用于合并相邻扇区的请求。例如,对扇区3-6、6-7、7-9的请求可以合并 为对扇区3-9的一个请求。即便 SSD 或 NVM 的随机访问和顺序访问响应时间相同, 合并顺序访问的请求仍可减少单独请求的数量。这种合并请求的技术称为 plugging。h]hX>暂存队列可用于合并相邻扇区的请求。例如,对扇区3-6、6-7、7-9的请求可以合并 为对扇区3-9的一个请求。即便 SSD 或 NVM 的随机访问和顺序访问响应时间相同, 合并顺序访问的请求仍可减少单独请求的数量。这种合并请求的技术称为 plugging。}(hj^hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKDhj?hhubh)}(h此外,I/O 调度器还可以对请求进行重新排序以确保系统资源的公平性(例如防止某 个应用出现“饥饿”现象)或是提高 I/O 性能。h]h此外,I/O 调度器还可以对请求进行重新排序以确保系统资源的公平性(例如防止某 个应用出现“饥饿”现象)或是提高 I/O 性能。}(hjlhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKHhj?hhubjw)}(hhh](j|)}(h I/O 调度器h]h I/O 调度器}(hj}hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjzhhhhhKLubh)}(hX2块层实现了多种调度器,每种调度器都遵循一定启发式规则以提高 I/O 性能。它们是 “可插拔”的(plug and play),可在运行时通过 sysfs 选择。你可以在这里阅读更 多关于 Linux IO 调度器知识 `here `_。调度只发 生在同一队列内的请求之间,因此无法合并不同队列的请求,否则会造成缓存冲突并需 要为每个队列加锁。调度后,请求即可发送到硬件。可能选择的调度器之一是 NONE 调 度器,这是最直接的调度器:它只将请求放到进程所在的软件队列,不进行重新排序。 当设备开始处理硬件队列中的请求时(运行硬件队列),映射到该硬件队列的软件队列 会按映射顺序依次清空。h](h块层实现了多种调度器,每种调度器都遵循一定启发式规则以提高 I/O 性能。它们是 “可插拔”的(plug and play),可在运行时通过 sysfs 选择。你可以在这里阅读更 多关于 Linux IO 调度器知识 }(hjhhhNhNubj))}(hA`here `_h]hhere}(hjhhhNhNubah}(h]h ]h"]h$]h&]namehererefuri7https://www.kernel.org/doc/html/latest/block/index.htmluh1j(hjubhtarget)}(h: h]h}(h]hereah ]h"]hereah$]h&]refurijuh1j referencedKhjubhX。调度只发 生在同一队列内的请求之间,因此无法合并不同队列的请求,否则会造成缓存冲突并需 要为每个队列加锁。调度后,请求即可发送到硬件。可能选择的调度器之一是 NONE 调 度器,这是最直接的调度器:它只将请求放到进程所在的软件队列,不进行重新排序。 当设备开始处理硬件队列中的请求时(运行硬件队列),映射到该硬件队列的软件队列 会按映射顺序依次清空。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKNhjzhhubeh}(h]i-oah ]h"] i/o 调度器ah$]h&]uh1jvhj?hhhhhKLubeh}(h]id4ah ]h"]软件暂存队列ah$]h&]uh1jvhjhhhhhKdispatch``) 中。 随后,当块层下次运行该队列时,会优先发送位于 ``dispatch`` 链表中的请求, 以确保那些最早准备好发送的请求能够得到公平调度。硬件队列的数量取决于硬件及 其设备驱动所支持的硬件上下文数,但不会超过系统的CPU核心数。在这个阶段不 会发生重新排序,每个软件队列都有一组硬件队列来用于提交请求。h](hO如果请求无法直接发送到硬件,它们会被加入到请求的链表(}(hjhhhNhNubhliteral)}(h``hctx->dispatch``h]hhctx->dispatch}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhL) 中。 随后,当块层下次运行该队列时,会优先发送位于 }(hjhhhNhNubj)}(h ``dispatch``h]hdispatch}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhXK 链表中的请求, 以确保那些最早准备好发送的请求能够得到公平调度。硬件队列的数量取决于硬件及 其设备驱动所支持的硬件上下文数,但不会超过系统的CPU核心数。在这个阶段不 会发生重新排序,每个软件队列都有一组硬件队列来用于提交请求。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK_hjhhubh)}(hl块层和设备协议都不保证请求完成顺序。此问题需由更高层处理,例如文件系统。h]h)}(hj$h]hl块层和设备协议都不保证请求完成顺序。此问题需由更高层处理,例如文件系统。}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKghj"ubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubeh}(h]id5ah ]h"]硬件派发队列ah$]h&]uh1jvhjhhhhhKYubjw)}(hhh](j|)}(h基于标识的完成机制h]h基于标识的完成机制}(hjDhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjAhhhhhKjubh)}(hX为了指示哪一个请求已经完成,每个请求都会被分配一个整数标识,该标识的取值范围 是从0到分发队列的大小。这个标识由块层生成,并在之后由设备驱动使用,从而避 免了为每个请求再单独创建冗余的标识符。当请求在驱动中完成时,驱动会将该标识返 回给块层,以通知该请求已完成。这样,块层就无需再进行线性搜索来确定是哪一个 I/O 请求完成了。h]hX为了指示哪一个请求已经完成,每个请求都会被分配一个整数标识,该标识的取值范围 是从0到分发队列的大小。这个标识由块层生成,并在之后由设备驱动使用,从而避 免了为每个请求再单独创建冗余的标识符。当请求在驱动中完成时,驱动会将该标识返 回给块层,以通知该请求已完成。这样,块层就无需再进行线性搜索来确定是哪一个 I/O 请求完成了。}(hjRhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKlhjAhhubeh}(h]id6ah ]h"]基于标识的完成机制ah$]h&]uh1jvhjhhhhhKjubeh}(h]jah ]h"] 工作原理ah$]h&]uh1jvhjhhhhhK-jKubjw)}(hhh](j|)}(h 更多阅读h]h 更多阅读}(hjrhhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjohhhhhKsubh bullet_list)}(hhh](h list_item)}(hR`Linux 块 I/O:多队列 SSD 并发访问简介 `_ h]h)}(hQ`Linux 块 I/O:多队列 SSD 并发访问简介 `_h](j))}(hjh]h0Linux 块 I/O:多队列 SSD 并发访问简介}(hjhhhNhNubah}(h]h ]h"]h$]h&]name0Linux 块 I/O:多队列 SSD 并发访问简介jhttp://kernel.dk/blk-mq.pdfuh1j(hjubj)}(h h]h}(h] linux-i-o-ssdah ]h"]0linux 块 i/o:多队列 ssd 并发访问简介ah$]h&]refurijuh1jjKhjubeh}(h]h ]h"]h$]h&]uh1hhhhKuhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(hA`NOOP 调度器 `_ h]h)}(h@`NOOP 调度器 `_h](j))}(hjh]hNOOP 调度器}(hjhhhNhNubah}(h]h ]h"]h$]h&]nameNOOP 调度器j,https://en.wikipedia.org/wiki/Noop_scheduleruh1j(hjubj)}(h/ h]h}(h]noopah ]h"]noop 调度器ah$]h&]refurijuh1jjKhjubeh}(h]h ]h"]h$]h&]uh1hhhhKwhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h[`Null 块设备驱动程序 `_ h]h)}(hZ`Null 块设备驱动程序 `_h](j))}(hjh]hNull 块设备驱动程序}(hjhhhNhNubah}(h]h ]h"]h$]h&]nameNull 块设备驱动程序j:https://www.kernel.org/doc/html/latest/block/null_blk.htmluh1j(hjubj)}(h= h]h}(h]nullah ]h"]null 块设备驱动程序ah$]h&]refurijuh1jjKhjubeh}(h]h ]h"]h$]h&]uh1hhhhKyhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubeh}(h]h ]h"]h$]h&]bullet-uh1jhhhKuhjohhubeh}(h]id7ah ]h"] 更多阅读ah$]h&]uh1jvhjhhhhhKsubeh}(h]id1ah ]h"]介绍ah$]h&]uh1jvhjxhhhhhKubjw)}(hhh](j|)}(h 源代码h]h 源代码}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hj2hhhhhK|ubh)}(h该API在以下内核代码中:h]h该API在以下内核代码中:}(hjChhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK~hj2hhubh)}(hinclude/linux/blk-mq.hh]hinclude/linux/blk-mq.h}(hjQhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj2hhubh)}(hblock/blk-mq.ch]hblock/blk-mq.c}(hj_hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj2hhubeh}(h]id8ah ]h"] 源代码ah$]h&]uh1jvhjxhhhhhK|ubeh}(h] i-o-blk-mqah ]h"],多队列块设备 i/o 排队机制 (blk-mq)ah$]h&]uh1jvhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(j{N generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerjerror_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames} 工作原理]jasrefids}nameids}(jzjwj/j,jjjljjjjjjjj>j;jejbj'j$jjjjj jjrjou nametypes}(jzj/jjljjjj>jej'jjj jruh}(jwjxj,jjjjjjj?jjzjjj;jjbjAj$jojjjjjjjoj2u footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}jKsRparse_messages]transform_messages] transformerN include_log]1Documentation/translations/zh_CN/block/blk-mq.rst(NNNNta decorationNhhub.