iflag = fullblockなしの猫| ddパイプのために部分的な読み取りが発生しますが、なぜ128KiBに切り捨てられますか?

iflag = fullblockなしの猫| ddパイプのために部分的な読み取りが発生しますが、なぜ128KiBに切り捨てられますか?

次の1MiBファイルの例を考えてみましょう。

$ 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ブロックあたり128KiB以上を読み取ることができません。ddiflag=fullblock

$ 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.html65536バイトに設定されているようです。

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

(Python3では動作しませんでした。https://bugs.python.org/issue20074)

主な質問は(純粋な好奇心)です。なぜ読み取りは128KiBに切り捨てられますか?

(Arch Linux、カーネル5.4.2、zsh 5.7.1でテスト済み)

答え1

これより大きいブロックサイズPIPE_BUF(最新のUNIXでは5k、Linuxでは4k)は、断片化なしでパイプを通過できません。

これは次のことを意味します。可能分割されていますが、どの分割でも資金はサポートされていません。

より多くの読み取りが可能かどうかは、PIPE_BUFカーネルのメモリ状態によって異なります。カーネルは、カーネルがすべてのカーネルメモリを占有しないように書き込み側を停止するタイミングを制御します。また、読み出し側のタイミングとスケジューリング、そして十分な量のデータが蓄積された後に起きるかどうかに依存します。

注:dd名前付きオプションはiflag=fullblockベンダー固有の拡張です。非標準なので使用しないでください。

また、使用される書き込みブロックサイズgcatは128kですが、UNIXバージョンcatは。mmap()8Mbyte

関連情報