5

我有一个生成大量 SCSI 写入的用户空间应用程序(详情如下)。但是,当我查看到达 SCSI 目标的 SCSI 命令(即存储,由 FC 连接)时,某些东西会将这些写入分成 512K 块。

该应用程序基本上直接将 1M 大小的直接写入设备:

fd = open("/dev/sdab", ..|O_DIRECT);
write(fd, ..., 1024 * 1024);

此代码导致发送两个 SCSI WRITE,每个 512K。

但是,如果我发出直接 SCSI 命令,没有块层,写入不会拆分。我从命令行发出以下命令:

sg_dd bs=1M count=1 blk_sgio=1 if=/dev/urandom of=/dev/sdab oflag=direct

我可以看到一个 1M 大小的 SCSI WRITE。

问题是,什么是拆分写入,更重要的是,它是否可配置?Linux 块层似乎是有罪的(因为 SG_IO 没有通过它)并且 512K 似乎太随意了,不是某种可配置的参数。

4

5 回答 5

3

如对“为什么我的 IO 请求的大小被限制为大约 512K” Unix 和 Linux 堆栈交换问题的回答以及内核块层的“当 2MB 变成 512KB ”文档的“设备限制”部分中所述维护者 Jens Axboe,这可能是因为您的设备和内核有大小限制(在 中可见/sys/block/<disk>/queue/):

  • max_hw_sectors_kb硬件可以接受的单个 I/O 的最大大小
  • max_sectors_kb块层将发送的最大大小
  • max_segment_size以及max_segmentsDMA 引擎对分散聚集 (SG) I/O 的限制(每个段的最大大小和单个 I/O 的最大段数)

当 I/O 来自的缓冲区不连续时,段限制很重要,在最坏的情况下,每个段可以小到页面(在 x86 平台上为 4096 字节)。这意味着一个 I/O 的 SG I/O 可以限制为 4096 * 的大小max_segments

问题是,什么是分裂写

正如您猜到的那样,Linux 块层。

而且,更重要的是,它是否可配置?

您可以摆弄,max_sectors_kb但其余部分是固定的,并且来自设备/驱动程序限制(所以我猜测在您的情况下可能不是,但由于内存碎片较少,您可能会在重新启动后直接看到更大的 I/O)。

512K 似乎太随意了,不是某种可配置的参数

该值可能与片段 SG 缓冲区有关。假设您在 x86 平台上并且有一个这样max_segments128

4096 * 128 / 1024 = 512

这就是 512K 的来源。

额外的喋喋不休:根据https://twitter.com/axboe/status/1207509190907846657,如果您的设备使用 IOMMU 而不是 DMA 引擎,那么您不应该受到分段限制......

于 2019-12-19T04:26:27.720 回答
1

块驱动程序的每个请求属性有一个最大扇区。我必须检查如何修改它。您曾经能够通过 blockdev --getmaxsect 获得这个值,但我没有在我的机器的 blockdev 上看到 --getmaxsect 选项。

于 2012-06-10T19:24:58.643 回答
1

责任确实在块层上,SCSI层本身与大小无关。您应该检查底层是否确实能够传递您的请求,尤其是对于直接 io,因为它可能被分成许多小页面,并且需要一个比硬件可以支持的更长的分散收集列表或甚至只是驱动程序(libata 是/有点受限)。

您应该查看并调整 /sys/class/block/$DEV/queue 那里有各种文件,最有可能匹配您需要的是 max_sectors_kb 但您可以尝试一下,看看哪些适合您。您可能还需要调整分区变量。

于 2012-07-14T20:59:04.853 回答
0

查看以下文件应该会告诉您逻辑块大小是否不同,在您的情况下可能是 512。但是,我不确定您是否可以写入这些文件来更改这些值。(即逻辑块大小)

/sys/block/<disk>/queue/physical_block_size 
/sys/block/<disk>/queue/logical_block_size
于 2012-05-14T17:47:59.300 回答
0

试试 ioctl(fd, BLKSECTSET, &blocks)

于 2013-02-16T02:56:33.107 回答