web-dev-qa-db-ja.com

ディスクがいっぱいになるまで、 `tar`から` dd`へのパイプ処理が停止しないのはなぜですか?

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

$ 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カートに書き込まれた後に停止し、スペースが不足することはありません。

18
con-f-use

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

bs=1Mを使用していますが、標準入力、パイプからの読み取りは、読み取りが少なくなります。実際、ddによれば、1回の完全な読み取りは行われていません。

次に、不完全な読み取りをゼロで補完するconv=syncがあります。

0+15281 records in
15280+0 records out

ddは、完全な読み取り0回と不完全な読み取り15281回を受信し、完全なブロック15280個を書き込みました(conv = syncがゼロで埋められています)。したがって、スペースがなくなるまで、出力は入力よりはるかに大きくなります。

   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を追加します。


説明のために、デフォルトで無限の「y\ny\ny\n」を生成するyesを検討してください。

$ 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をゼロ(0x01e000-0x100000、925696バイト)として書き込みます。ほとんどの場合、これが発生することは望ましくありません。各読み取りがどの程度不完全になるかを実際に制御できないため、結果はとにかくランダムです。このように、2番目の読み取りは122880バイトではなく、73728バイトです。

dd conv=syncが役立つことはめったになく、読み取りエラーが発生したときにゼロを書き込むなど、それが歓迎される場合でも 事態はひどく間違ってしまいます。

50
frostschutz