9.1. 直接 IO

直接 IO 使用 kiobuf 机制 [参见 Linux 设备驱动程序 一书] 来操作用户空间内分配的内存,以便更低层级(适配器)驱动程序可以直接 DMA 到或从该用户空间内存进行数据传输。由于用户可以为通过 sg 接口传递的每个 SCSI 命令提供不同的数据缓冲区,因此 kiobuf 机制需要为每个 SCSI 命令设置其结构(并撤销该设置)。[1] 直接 IO 在 sg 3.1.18 中作为一个选项提供(在此之前,需要重新编译 sg 驱动程序并修改一个宏定义)。直接 IO 支持的设计方式是,如果请求了直接 IO 但无法执行,则仍将使用间接 IO 执行该命令。如果请求了直接 IO 并且已执行,则在请求完成后,sg_io_hdr_t 控制结构的 'info' 成员中将设置 SG_INFO_DIRECT_IO 位。ISA SCSI 适配器不支持直接 IO,因为它们只能寻址 24 位地址空间。

直接 IO 的一个限制是 sg_io_hdr_t::iovec_count==0。因此,用户目前无法在同一请求中同时使用应用程序级别的 scatter gather 和直接 IO。

为了使直接 IO 值得使用,应该请求合理数量的数据进行数据传输。对于小于 8 KB 的传输,可能不值得这样做。另一方面,为直接 IO “锁定” 多个 512 KB 数据块可能会对整体系统性能产生不利影响。请记住,在直接 IO 请求期间,数据传输缓冲区会映射到固定的内存位置并锁定,使其不会被换出。如果过度使用,这可能会“限制”内核的灵活性。

在 sg 3.1.18 之前,直接 IO 代码被 “SG_ALLOW_DIO” 宏定义注释掉。在 sg 3.1.18 中(适用于 lk 2.4.2 及更高版本),直接 IO 代码处于活动状态,但默认情况下由运行时值关闭。可以通过 “proc” 文件系统在以下位置访问此值/proc/scsi/sg/allow_dio。当具有 root 权限的用户向该文件写入 “1” 时,直接 IO 将被启用: echo 1 > /proc/scsi/sg/allow_dio 。如果在 sg_io_hdr::flags 中设置了 SG_FLAG_DIRECT_IO,但/proc/scsi/sg/allow_dio值为 “0”,则将执行间接 IO(这在请求完成后通过 ((sg_io_hdr::info & SG_INFO_DIRECT_IO_MASK) == SG_INFO_INDIRECT_IO) 指示)。

注意

[1]

遗憾的是,在某些 lk 2.4 系列版本中,该设置时间足够长,会对直接 IO 性能产生不利影响。此外,用户空间中 malloc() 分配的内存往往由 SCSI 适配器看到的非连续页组成。这要求 sg 驱动程序构建高度分散的 scatter gather 列表,这是不太理想的。这会将最大传输大小限制为 [(max_scsi_adapter_scatter_gather_elements - 1) * PAGE_SIZE]。[这是一种与用户在基于 iovec 的 sg 接口中看到的 _不同_ 的 scatter gather 机制。]