我为什么不能写入最后一个块的最后一个字节?

我为什么不能写入最后一个块的最后一个字节?

我正在进行一些测试,通过以 512 字节的块大小(我的驱动器上的块大小)写入随机数据模式,并且 dd 在最后一个块处失败,提示设备空间不足。

我正在环回设备上进行这些测试只是为了验证我的方法是否正确,所以我知道这不是一个坏驱动器。

fdisk -l /dev/loop18显示:

Disk /dev/loop18: 24 MiB, 25165824 bytes, 49152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

太棒了。所以我们总共有 49152 个扇区,每个扇区 512 字节,就像我提到的那样。除了最后一个扇区外,每个扇区都可以写入,就像我提到的那样。

这样做:sudo dd if="pattern2.img" of=/dev/loop18 count=1 seek=49152 bs=512'pattern2.img' 是从输出写入的单个 512 块/dev/urandom

dd: error writing '/dev/loop18': No space left on device
1+0 records in
0+0 records out
0 bytes copied, 0.000167895 s, 0.0 kB/s

但是……如果我们这样做:sudo dd if="pattern2.img" of=/dev/loop18 count=1 seek=49152 bs=511我们不会得到任何错误。所以它在最后一个字节写入失败。为什么?

如果您怀疑该随机图像:

Disk pattern2.img: 512 B, 512 bytes, 1 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

以及十六进制转储:

0000000 9349 7306 5ffe 5cff 7e01 4596 6a15 e5f6
0000010 c7ff 1a1d 7cc7 861a e907 f0e9 b0fb 8fb4
0000020 1931 5660 0b6b 2101 243e fb58 1c4d 2c55
0000030 376a 062d 308c 647c 9d2d a791 304f aa21
0000040 2831 4d43 9ad8 cefc f880 7077 0948 5966
0000050 e1fa c2ee a43e fcdb 97cf 9479 5bca e6ee
0000060 2a70 eeba 322b ff22 3688 d636 eaea eb03
0000070 c15f 5468 a1cc 172f fba1 8863 a1b0 5d75
0000080 fba5 335c e1ad 1ed4 db26 1607 9822 0c71
0000090 0080 1023 1845 a006 93ca ec13 ddcc 31d1
00000a0 585c f258 e3f9 4b93 14f1 7d21 160b 132f
00000b0 1112 546a baa5 2bcf 2af0 3e9b 8ca0 8ba7
00000c0 424a a730 4799 2d43 bb42 b6d4 0f0f 97d8
00000d0 f06c 6da5 6233 d17c da04 81e7 0533 8dae
00000e0 6d14 96ab f946 4148 5f8c ce78 0f5d ea22
00000f0 f827 4766 8ebb 9a8f 08b7 2355 8fa2 77eb
0000100 c691 5ee9 4f43 3bd6 fc24 9d30 0b42 8f14
0000110 f839 68c1 abd9 cd38 ccc5 1de6 560c 24b3
0000120 810a ec22 270a f882 0de3 9994 6b2b a581
0000130 b5c9 ebcb 2122 28d3 2ad3 a370 c633 3cb4
0000140 90f0 4da5 4a05 03a0 a286 ca44 9404 427a
0000150 18b9 9b10 535a 8b9e f7a2 5018 648b f107
0000160 4dea a1f6 93a1 3e12 d019 e1ff 4347 a9d2
0000170 1942 64fd 303f 3a6b 24af 9bea 78dd 9a16
0000180 e6d7 14d3 896e 8cf7 554f 25e3 02d0 1b46
0000190 6fc1 dc99 7fb1 8620 0fd5 c2f4 042d b9bb
00001a0 366f 8231 388d 0c17 66a3 d6f7 16bd bc62
00001b0 ab86 27a7 a151 e8f3 2e73 371b e123 abf0
00001c0 98c7 d0fd b0d7 6fe6 f4bb d025 b8a8 0bc9
00001d0 5215 50fc 8f8e 9757 0b1f 4dec 788e dd6f
00001e0 64c8 6bf5 e925 1325 02fb d29c f40b 9978
00001f0 99c1 a734 1e7d fd5d a75f d54d ab9b 05a8
0000200

这是 512 字节的数据。0000200 确实出现了,但它是空的。

所以...作为最后的健全性检查:sudo dd if="/dev/urandom" of=/dev/loop18 count=1 seek=49152 bs=512以同样的方式失败。

怎么会这样?这是怎么回事?

答案1

块设备中正好有 49152 个 512 字节扇区/dev/loop18seek=49152 bs=512你跳过了它们全部。在您dd开始写入之前,它已经准确地位于输出文件的末尾。

如果它是常规文件,那么从末尾开始的写入会将数据附加到其中。但它/dev/loop18不是常规文件,其大小是固定的,您无法通过这种方式扩展它。无论如何,扩展并不是您的意图。

要写入最后一个扇区,您需要跳过所有以前的扇区,没有了。最后一个扇区前有 49151 个扇区,因此使用bs=512 seek=49151

您的困惑可能是由以下观察结果引起的(可能是您读过的其他人的观察结果),即要写入扇区号 N,您需要seek=N。 陷阱在于编号:它从 0 开始(即初始扇区是第 0 个),因此如果有 49152 个扇区,则最后一个扇区的编号为 49151。

一般情况下记得dd是一个难以正确使用且不稳定的工具。然而在这种情况下,您只是跳过了大部分输出。


您将seek=49152 bs=511跳过 49152 个 511 字节的输出块,因此距离结尾还有 48 KiB,远远没有到达最后一个字节。注意bs同时指定了ibsobs

要将任意数量的字节写入最后一个 512 字节扇区,您仍然需要跳过输出中除一个 512 字节扇区之外的所有扇区,因此您需要obs=512 seek=49151。要在那里写入恰好 511 个字节,您需要。在这种情况下,将和设置为不同的值ibs=511 count=1很有用。ibsobs

相关内容