Tại sao đường ống `tar` vào` dd` không dừng lại cho đến khi đĩa đầy?


18

Tôi có một kho lưu trữ tar của một hình ảnh đĩa đơn. Hình ảnh bên trong tập tin tar này có kích thước khoảng 4GB. Tôi chuyển đầu ra tar xfthành ddđể ghi ảnh đĩa vào thẻ SD. Đĩa mềm không bao giờ dừng cho đến khi thẻ đầy. Đây là phiên shell của tôi:

$ 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

Tại sao? Nó nên dừng lại sau khi nhấn đã ghi hình ảnh 4GB vào giỏ hàng 16 GB và không bao giờ hết dung lượng!


Bạn có không gian đĩa để thử chạy nó qua ddvà ghi nó vào một tập tin khác không? tar zxf disk.img.tgz -O | dd status=progress conv=sync bs=1M of=/path/to/some/file/on/disk? Nếu vậy, điều đó có giúp bạn có một bản sao chính xác của tập tin gốc không?
Andy Dalton

2
Tại sao bạn có conv=sync? Có phải bạn muốn sử dụng conv=fsynccó lẽ?
Ralph Rönnquist

Bạn có chắc chắn đó là kích thước thật của tập tin? Tôi biết gzip chỉ có 32 bit để lưu trữ kích thước tệp, do đó, nó có kích thước tệp trên 4GB sai. Tôi không chắc chắn nếu tar có một giới hạn tương tự.
David Conrad

Câu trả lời:


50

Đó là bởi vì bạn đang làm sai.

Bạn đang sử dụng bs=1Mnhưng đọc từ stdin, pipe, sẽ có số lần đọc nhỏ hơn. Trong thực tế, theo dd, bạn đã không nhận được một lần đọc đầy đủ.

Và sau đó bạn có conv=syncbổ sung đọc không đầy đủ với số không.

0+15281 records in
15280+0 records out

ddđã nhận được 0 bản đầy đủ và 15281 lượt đọc không đầy đủ và đã viết 15280 khối đầy đủ (conv = sync zero fill). Vì vậy, đầu ra lớn hơn nhiều so với đầu vào, cho đến khi bạn không còn chỗ trống.

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

Để giải quyết điều này, bạn có thể loại bỏ conv=syncvà thêm iflag=fullblock.


Để minh họa, hãy xem xét yes, theo mặc định sẽ phun ra "y \ ny \ ny \ n" vô hạ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.|
*

Với dd bs=1M conv=syncnó trông như thế này:

$ 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  |................|
*

Vì vậy, nó nhận được một khối không hoàn chỉnh là "y \ ny \ ny \ n" (0x00000 - 0x1e000, 122880 Byte) sau đó ghi 1M còn lại dưới dạng số 0 (0x01e000 - 0x100000, 925696 Byte). Trong hầu hết các trường hợp, bạn không muốn điều này xảy ra. Dù sao thì kết quả là ngẫu nhiên vì bạn không có quyền kiểm soát thực sự đối với việc mỗi lần đọc không hoàn thành như thế nào. Giống như ở đây, lần đọc thứ hai không còn là 122880 Byte mà là 73728 Byte.

dd conv=synchiếm khi hữu ích và ngay cả trong trường hợp nó sẽ được chào đón, như viết số 0 khi bạn gặp lỗi đọc, mọi thứ sẽ trở nên sai lầm khủng khiếp với nó.


Trong trường hợp này, việc chạy ddlệnh bên dưới strace(giả sử Linux) sẽ chỉ ra rằng mỗi lần đọc ngắn từ đường ống được theo sau là ghi 1 MB đầy đủ.
Andrew Henle

2
@AndrewHenle thậm chí không cần bước đi cho việc này, chỉ cần nhìn vào đầu ra sẽ làm. Đã thêm một minh họa
frostschutz

Điều này cũng minh họa tại sao ddlệnh bị phá vỡ cơ bản và không sử dụng được. Nó được chỉ định để hoạt động trong từng reads write, nhưng các thao tác đó được chỉ định sao cho chúng luôn có thể tạo ra các lần đọc hoặc ghi ngắn và đó không phải là một lỗi. Hậu quả là hành vi của ddphụ thuộc vào hành vi không xác định.
R ..

Cảm ơn câu trả lời rất giáo dục. Như một người khác đề nghị tôi là một con lừa và trộn lẫn nhiều lựa chọn dd, nhưng nó khiến tôi học được điều gì đó từ bạn. Điều tôi vẫn chưa hoàn toàn chắc chắn là, nếu và khi nào ddsẽ chấm dứt. Tôi giả sử, nó sẽ có, nhưng vì nó thực sự đang viết 1 phần dữ liệu thực tế và 9 phần không, nên nó sẽ dừng lại sau khi viết khoảng 40G. Đúng không?
con-f-sử dụng

@R .., tính năng đó rất hữu ích với trình điều khiển thiết bị quan tâm đến kích thước khối của đọc và ghi. Tôi nhớ sử dụng một số ổ đĩa băng quan tâm đến nó. Mặc dù trong trường hợp này, rõ ràng là không cần thiết, người ta chỉ có thể chuyển hướng trực tiếp vào đĩa (mặc dù không nhận được báo cáo tiến độ trực tiếp)
ilkkachu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.