Рассмотрим этот образец файла размером 1 МБ:

$ dd if=/dev/zero of=input.img bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00100595 s, 1.0 GB/s

Если я попытаюсь cat передать его в dd без использования iflag=fullblock, я не смогу прочитать более 128 КБ на блок:

$ cat input.img | dd of=output.img bs=128k count=1
1+0 records in
1+0 records out
131072 bytes (131 kB, 128 KiB) copied, 0.000221117 s, 593 MB/s
$ cat input.img | dd of=output.img bs=129k count=1
0+1 records in
0+1 records out
131072 bytes (131 kB, 128 KiB) copied, 0.000495317 s, 265 MB/s
$ cat input.img | dd of=output.img bs=1M count=1
0+1 records in
0+1 records out
131072 bytes (131 kB, 128 KiB) copied, 0.000437209 s, 300 MB/s

Используя 2 счетчика блоков, он даже выводит предупреждение:

$ cat input.img | dd of=output.img bs=129k count=2
dd: warning: partial read (131072 bytes); suggest iflag=fullblock
0+2 records in
0+2 records out
262144 bytes (262 kB, 256 KiB) copied, 0.00107657 s, 243 MB/s

Я думал, что это может быть связано с размером буфера канала, однако я проверил его размер после https://www.golinuxhub.com/2018/05/how-to-view-and-increase-default-pipe-size-buffer.html и вроде установлено 65536 байт:

$ mkfifo /tmp/testfifo
$ python2
>>> fifo_fd = open('/tmp/testfifo', 'rb+')
>>> import fcntl
>>> fcntl.fcntl(fifo_fd, 1032)
65536

(Обратите внимание, что я не мог заставить его работать с Python3, я думаю, из-за https://bugs.python.org/issue20074 )

Главный вопрос (чистое любопытство): почему чтение усекается до 128 КБ?

(Проверено на Arch Linux, ядро ​​5.4.2, zsh 5.7.1.)

0
Stephen Kitt 16 Июн 2020 в 14:53
1
Вы творчески интерпретировали статью, на которую ссылаетесь: в своем фрагменте python вы пытаетесь установить минимальное значение размера канала с помощью fcntl(fifo_fd, F_SETPIPE_SZ, 0). Если вы хотите получить значение по умолчанию, вы должны использовать fcnt(fifo_fd, F_GETPIPE_SZ). Значение по умолчанию, безусловно, равно 65536, но его можно увеличить до значения в /proc/sys/fs/pipe-max-size.
 – 
mosvy
7 Дек 2019 в 13:40
Что касается того, почему dd читает куски по 128 КБ, когда вы запросили 129 КБ, это потому, что read(.., 129k) вернул 128 КБ. Нет никакой гарантии, что чтение не вернет более короткий счет, чем запрошено, и это неразумное предположение, поскольку оно будет делать это очень редко. На справочной странице dd говорится об аргументе bs=BYTES: "чтение и запись до БАЙТОВ байтов", а не "точно БАЙТОВ байтов".
 – 
mosvy
7 Дек 2019 в 13:46
Ваше утверждение неверно, посмотрите, что я разместил за 2 часа до того, как вы разместили свой комментарий. читается 128k, потому что программа gcat пишет только 128k и не больше.
 – 
schily
7 Дек 2019 в 20:14
Какое утверждение неверно? Я проверил тестовый пример OP, и он говорит read(0, ..., 132096) = 131072. А вторая часть — буквальная цитата из справочной страницы dd(1).
 – 
mosvy
7 Дек 2019 в 20:22
Что вы ожидаете от этого теста? Вопрос заключался в том, почему он не может вернуть больше, чем 128 КБ, и это, конечно, результат размера write(), используемого gcat.
 – 
schily
7 Дек 2019 в 20:35

1 ответ

Лучший ответ

Любой блок размером более PIPE_BUF (5 КБ в современной UNIX, 4 КБ в Linux) не может передаваться по каналу без фрагментации.

Это означает, что его может разделить, но права на разделение нет.

Способны ли вы читать больше, чем PIPE_BUF, зависит от состояния памяти ядра, которое контролирует, когда сторона записи останавливается ядром, чтобы предотвратить использование всей памяти ядра. Это также зависит от времени и планирования стороны чтения и от того, будет ли она пробуждаться после того, как будет накоплено достаточное количество данных.

Кстати: опция dd с именем iflag=fullblock является расширением, специфичным для поставщика. Избегайте его использования, так как он нестандартен.

Также обратите внимание, что gcat использует размер блока записи 128 КБ, в то время как версия cat для UNIX основана на mmap() и использует размер записи 8Mbyte. Таким образом, если вы запустите этот тест на генетическом UNIX, вы сможете прочитать блоки размером более 128 КБ,

3
schily 7 Дек 2019 в 14:36
Fullblock может быть расширением для конкретного поставщика, но он поддерживается многими поставщиками: GNU dd, Busybox dd и Toybox dd поддерживают iflag=fullblock — знаете ли вы современный dd, который его не поддерживает?
 – 
hanshenrik
8 Дек 2021 в 23:38