Чому трубопровід `tar` у` dd` не зупиняється, поки диск не заповниться?


18

У мене є архів дьогтю одного образу диска. Зображення всередині цього файлу з дьогтем розміром близько 4 Гб. Я передаю висновок 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

Чому? Він повинен зупинитися після того, як хіт записав зображення на 4 Гб у візок 16 Гб і ніколи не вистачить місця!


Чи є у вас дисковий простір, щоб спробувати запустити це ddі записати його в інший файл? tar zxf disk.img.tgz -O | dd status=progress conv=sync bs=1M of=/path/to/some/file/on/disk? Якщо так, то чи отримуєте ви точну копію оригінального файлу?
Енді Далтон

2
Чому у вас є conv=sync? Ви мали на увазі використовувати, conv=fsyncможливо?
Ральф Ронквіст

Ви впевнені, що це справжній розмір файлу? Я знаю, що в gzip є лише 32 біти, в яких можна зберігати розміри файлів, тому розмір файлів, розміром понад 4 Гб, не відповідає. Я не впевнений, чи має дьоготь подібне обмеження.
Девід Конрад

Відповіді:


50

Це тому, що ти робиш це неправильно.

Ви використовуєте, bs=1Mале читання з stdin, pipe, матиме менші показання. Насправді, за даними dd, ви не отримали жодного повного читання.

І тоді ви маєте, conv=syncщо доповнює неповні читання нулями.

0+15281 records in
15280+0 records out

ddотримав 0 повних та 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 як нулі (0x01e000 - 0x100000, 925696 байт). У більшості випадків ви не хочете, щоб це сталося. Результат так чи інакше є випадковим, оскільки ви не маєте реального контролю над тим, наскільки виявиться неповне кожне прочитане. Як і друге читання, це вже не 122880 байт, а 73728 байт.

dd conv=syncрідко корисний і навіть у тих випадках, коли це було б бажано, як, наприклад, записувати нулі, коли ви отримуєте помилки читання, справи з цим будуть жахливо не так.


У цьому випадку запуск ddкоманди в strace(припускаючи Linux) показав би, що за кожним коротким зчитуванням з труби супроводжувалося повне записування в 1 МБ.
Ендрю Генле

2
@AndrewHenle навіть не потребує напруги для цього, лише дивлячись на результат, це зробить. Додано ілюстрацію
frostschutz

Це також ілюструє, чому ddкоманда принципово порушена і непридатна. Описано, щоб діяти в окремих reads і writes, але ці операції визначені таким чином, що вони завжди можуть створювати короткі читання або записи, і це не помилка. Як наслідок, поведінка Росії ddзалежить від не визначеної поведінки.
Р ..

Дякую за дуже повчальну відповідь. Як хтось інший запропонував мені бути дупою і змішав безліч варіантів dd, але це призвело до того, щоб я щось дізнався у вас. У чому я досі не повністю впевнений - це, якби і коли ddбуло б припинено. Я припускаю, що це було б, але оскільки він насправді записував 1 частину фактичних даних та 9 частин нулів, він би припинився після написання приблизно 40G. Це правильно?
con-f-use

@R .., ця функція дуже корисна для драйверів пристроїв, які дбають про розмір блоку читання та запису. Пам’ятаю, я використовував деякі стрічкові накопичувачі, які піклувалися про це. Хоча в цьому випадку, очевидно, це не потрібно, можна було б просто перенаправити безпосередньо на диск (не отримуючи звіт про прогрес в реальному часі)
ilkkachu
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.