ディスクがいっぱいになるまで `tar` を `dd` にパイプするのが止まらないのはなぜですか?

ディスクがいっぱいになるまで `tar` を `dd` にパイプするのが止まらないのはなぜですか?

単一ディスクイメージのtarアーカイブがあります。 tarファイル内の画像サイズは約4GBです。tar xf出力ddをSDカードにパイプします。カードがいっぱいになるまでディスクダンプは停止しません。これは私のシェルセッションです。

$ ls -l disk.img.tgz
-rw-r--r-- 1 confus confus 192M Okt  5 00:53

$ tar -tvf disk.img.tgz
-rw-r--r-- root/root 4294968320 2018-10-05 00:52 disk.img

$ lsblk -lb /dev/sdc
NAME MAJ:MIN RM        SIZE RO TYPE MOUNTPOINT
sdc    8:32   1 16022241280  0 disk

$ tar zxf disk.img.tgz -O | sudo dd status=progress conv=sync bs=1M of=/dev/sdc
[sudo] password for user: 
15992881152 bytes (16 GB, 15 GiB) copied, 212 s, 75,4 MB/s 
dd: error writing '/dev/sdc': No space left on device
0+15281 records in
15280+0 records out
16022241280 bytes (16 GB, 15 GiB) copied, 217,67 s, 73,6 MB/s

なぜ?ヒットが4GBの画像を16GBのカートに書き込んだ後は停止し、スペースが不足しません!

答え1

それはあなたが間違っているからです。

使用していますが、bs=1Mstdin、パイプの読み値は小さくなります。実際、ddによると、完全な内容を読むことはできません。

conv=syncその後、不完全な読み取りをゼロで埋めることができます。

0+15281 records in
15280+0 records out

dd0個の完全な読み取りと15281個の不完全な読み取りが受信され、15280個の完全なブロックが記録されました(conv =同期ゼロパディング)。したがって、残りのスペースがなくなるまで、出力は入力よりはるかに大きくなります。

   sync   pad  every  input  block  with  NULs to ibs-size; when used with
          block or unblock, pad with spaces rather than NULs

conv=syncこの問題を解決するには、削除して追加しますiflag=fullblock


これを説明するために、yes基本的に無限の数の「y \ ny \ ny \ n」が出力されることを考慮してください。

$ yes
y
y
y
^C
$ yes | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*

次のようになりますdd bs=1M conv=sync

$ yes | dd bs=1M conv=sync | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
0001e000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00100000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
00112000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*

したがって、不完全な「y \ ny \ ny \ n」ブロック(0x00000 - 0x1e000、122880バイト)を取得し、残りの1Mを0(0x01e000 - 0x100000、925696バイト)に書き込みます。ほとんどの場合、このようなことが発生したくありません。それにもかかわらず、各読み取りがどれほど不完全であるかを実際に制御できないため、結果はランダムです。ここでのように、2番目の読み取りはもはや122880バイトではなく73728バイトです。

dd conv=sync読み出しエラーが発生したときにゼロを書き込むなど、一般的な状況でもほとんど役に立ちません。状況が本当に悪くなる可能性があります。

関連情報