如何用随机位或零覆盖设备的开头?

如何用随机位或零覆盖设备的开头?

只是想用零或随机位覆盖设备的一小部分。更准确地说,我想覆盖所有扇区的前 1% 或几个 MiB。有没有一种简单的方法可以做到这一点?

答案1

尽管/dev/urandom速度非常慢并且因此不适合覆盖大量数据(整个磁盘),但它可能适合小区域。

覆盖 8MiB 的示例:

dd bs=1M count=8 iflag=fullblock if=/dev/urandom of=/dev/destroyme

或者您可以使用shred

shred -v -n 1 -s 8M /dev/destroyme

您还可以用来losetup创建特定大小和偏移量的设备,并使用没有自己的大小/偏移量选项的实用程序覆盖它们。

losetup --find --show --offset 0 --sizelimit $((8*1024*1024)) /dev/destroyme
# will print /dev/loopX
cat /dev/urandom > /dev/loopX
losetup -d /dev/loopX

答案2

与任何文件相同,用零覆盖前 10 MiB:

head -c10M < /dev/zero 1<> /dev/sdax

对于块设备文件,1<>甚至不需要不截断地打开,因为不存在截断块设备这样的事情,所以您可以简单地执行以下操作:

head -c10M < /dev/zero > /dev/sdax

并非所有头实现都支持-c,并且当它们支持时,并非所有都支持该M后缀(当它们支持时M可能意味着兆字节(1000000 字节),如ksh93内置head的或兆字节(1048576 字节),如 GNU head)。在这种情况下,您可以执行以下操作:

head -c "$((10 * 1024 * 1024)"

使其明确。

如果我们比较dd bs=1M count=10 < /dev/zero > /dev/sdax

  • 从概念上来说

    • head是从文件中读取指定数量的字节或行并将其写入 stdout 的命令
    • whiledd是一个低级命令,可以按照您想要的方式读取和写入数据。

    我在这里使用head它是因为它是为该任务设计的命令。dd如果我想针对特定用例进行优化,或者使用特定功能之一dd(另请参阅有关可移植性的注释),我会使用它。

  • 读+写循环:

    • head -c10M无论如何,都会尝试读取请求的数据,并且如果遇到错误,只会以非零退出状态失败。
    • dd bs=1M count=10,将执行 10 次读取(只要没有错误),并且对于返回一些数据的每次读取,使用读取的数据量执行相应的写入。仅当每次读取准确返回所请求的 1M 数据时,该方法才有效。实际上,对于 ,这是正确的/dev/zero,但在 Linux(至少 4.6)上,对于/dev/urandom,我无法在一次读取中获得超过 32MiB 减去 1 字节的数据(所以对于 1MiB 来说仍然可以,但如果你使用不同的版本,YMMV Linux 的),而对于/dev/random,只有几个字节(当前在熵池中的内容)。 GNU 实现dd具有iflag=fullblock持续读取直到请求缓冲区已满的行为head,但如果您没有 GNU dd,唯一的选择是一次执行 1 个字节读取,这会对性能产生巨大影响。
  • 性能:除了少量数据(少于几百兆字节)以外的任何数据(其中数据被写入稍后将刷新到磁盘的缓冲区或写入 )/dev/null,该过程将受到 I/O 限制。如果读取/dev/urandom/dev/random瓶颈将是随机数生成或磁盘 I/O。在这些情况下,您不会发现 dd 和 head 之间有太大区别。在任何情况下都head可能有更高的 CPU 开销(当性能受到 I/O 限制时不会被注意到)。

    • head是一个基本工具。实现将尝试尽可能高效地完成工作,同时仍然对所有类型的输入和输出都是可靠的,并且不会使用太多资源。它将执行与 相同的读+写循环dd,性能方面的主要区别是读取和写入的大小,这将决定进行的系统调用的数量。

      这些大小将取决于系统的实现和版本,head也可能取决于系统。在我的系统上使用最新版本的 GNU 时head,读取大小为 BUFSIZE(GNU 系统上为 8KiB),写入大小为 4KiB,尽管可以更改stdbuf -o 1M

      ksh93head内置函数似乎可以进行 64KiB 的读取和写入,并且不使用 libc 的 stdio,至少在我的系统上是这样。

      GNUhead使用 stdio 也意味着 stdio 产生额外的开销(其实现取决于系统)。

      当前版本的 GNUcat用于fadvise告诉系统它将按顺序读取数据,以便相应地优化缓存。某些实现head也可以做到这一点,或者将来也可以做到这一点,这并非不可能。dd由于是低级别的,我希望它只有在您告诉它的情况下才会执行(我不知道有任何dd实现具有此类支持)。

    • dd级别非常低,它会直接调用read()write()系统调用。除了使用 Linux 等专门的 API 之外,您无法获得比这更高的效率sendfile()

      read()它使您可以更好地控制和的大小write(),因此可以让您根据输入/输出的类型和可用资源进行优化。例如,如果您有大量可用内存,您不妨一次性读取整个数据(尽管在我的测试中,从 /dev/zero 复制到 /dev/null 时,我看不到过去任何显着的改进)块大小为 32KiB,性能甚至在块大小为 1MiB 之后开始下降)。

  • 可移植性

    -cbs=10M、都不conv=fullblock是便携式的。从文件中读取一定量数据的唯一 POSIX 命令是dd,但是要可靠地使用它(除了 on /dev/zero),如上所述,您需要bs=1这意味着可怕的性能。

  • 写入错误的后果。

    当尝试写入超过块设备末尾时,head和都会立即退出。dd如果磁盘有故障扇区,通常不会检测到,因为实际写入磁盘是异步的。通过 GNU 实现dd,您可以强制直接写入,oflag=direct这意味着dd将在出现第一个错误时停止。如果您想在第一个失败扇区之前写入尽可能多的数据,您可能需要使用默认块大小 512。

  • 读取错误的后果

    您不应在 /dev/zero、/dev/urandom 或 /dev/random 上收到任何读取错误。但更一般而言,headdd都会在第一次读取错误时退出并出现错误。使用dd,您可以使用 继续错误conv=noerror。在这种情况下,您可能需要添加选项sync( conv=noerror,sync),以便用零填充失败的块。head不会给你任何选择来做到这一点,因为它不是为此设计的。

备择方案。

  • pv -Ss 10M < /dev/zero > /dev/sdax将复制这 10M 并给你一个进度条。在我的测试中,默认读/写大小为 128KiB。您可以使用选项更改它-B,但在我的测试中,128KiB 已经给出了最佳结果。pv有一个-E相当于dds 的选项conv=noerror,sync

    在 Linux 上,它也有利于管道上的 I/O,因为它使用splice()系统调用来优化性能。

  • 如果你想玩sendfile()系统调用,你可以使用xfs_io.

    xfs_io -c 'sendfile -i src 0 10M' dst
    

    从 src 向 dst 发送 10M 数据。然而,它只做 sendfile()并且系统调用不能在/dev/zero,/dev/random或上使用/dev/urandom。但它可以用于稀疏文件。

     truncate -s 1T empty-file
     xfs_io -c 'sendfile -i empty-file 0 10M' /dev/sdax
    

    可以工作,但对于大量(几吉比字节),因为这是一个sendfile()系统调用,必须分配那么多内存,这意味着它的效率会低于dd bs=1M.理想情况下,我们希望sendfile()一次执行多个仅几兆字节的操作,但我不知道有任何命令可以做到这一点。

  • 对于/dev/zero输入,您实际上不需要您写入的每个块的数据。毕竟,这只是零。创建一个只有零的缓冲区很容易,而无需读取/dev/zero,并且我们可以在每次写入之间重用它。例如:

    PERLIO=:unix perl -e '$x = pack("x" . 1024*1024); print $x for 1..10000' > /dev/sdax
    

perl写入 10000 MiB比任何重复读取的解决方案效率更高(尽管有开销) /dev/zero

答案3

您可以使用将为您提供随机数据的设备dd来执行此操作。/dev/urandom一个例子 :

dd if=/dev/urandom of=/dev/sdX bs=1M count=100

这将写入 100MB 的随机数据:

  • if是输入文件
  • of是输出文件
  • bs=1M块大小为 1Mbyte
  • count这个块应该被写入多少次

您也可以使用输入文件/dev/zero/dev/null任何其他为您提供数据的文件。该命令将开始在输出文件/设备的开头写入数据。

相关内容