为什么直到磁盘装满后才将tar压缩到dd中?


18

我有一个磁盘映像的tar存档。该tar文件中的图片大小约为4GB。我将的输出传递tar xf到,dd以将磁盘映像写入SD卡。直到存储卡已满,磁盘转储才会停止。这是我的shell会话:

$ 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购物车后,它应该停止并且永远不会用完空间!


您是否有磁盘空间来尝试将其运行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吗?
拉尔夫·朗奎斯特(RalphRönnquist),

您确定这是文件的真实大小吗?我知道gzip只有32位用于存储文件大小,因此它将4GB以上的文件大小弄错了。我不确定tar是否有类似的限制。
戴维·康拉德

Answers:


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它很少有用,甚至在受欢迎的情况下(例如在读取错误时写零),事情也会变得非常糟糕。


在这种情况下,ddstrace(假设Linux)下运行命令将显示,每次从管道中读取短消息后,都会进行完整的1MB写操作。
安德鲁·亨利

2
@AndrewHenle甚至不需要strace,只需查看输出即可。添加了一个插图
frostschutz

这也说明了为什么该dd命令从根本上被破坏并且无法使用。它被指定为在单独的reads和writes中进行操作,但是对这些操作进行了指定,以使它们始终可以产生简短的读取或写入操作,这并不是错误。结果,的行为dd取决于未指定的行为。
R.,

感谢您提供非常有教育意义的答案。正如其他人所建议的那样,我是一个混混,把的许多选择混在一起dd,但这使我从您那里学到了一些东西。我仍然不完全确定的是,是否以及何时dd终止。我认为可以,但是由于它实际上只写了1个部分的实际数据和9个部分的零,因此在写入大约40G后它会停止。那是对的吗?
CON-F使用的

@R ..,此功能对于关心读写块大小的设备驱动程序非常有用。我记得使用过一些关心它的磁带机。尽管在这种情况下,这显然不是必需的,但可以将其直接重定向到磁盘(但是不会获得实时进度报告)
ilkkachu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.