Как можно использовать `dd` для блоков данных с правом сдвига?

Рассмотрим простой блок-блок на 100 МБ. Это 204800 блоков по 512 байт на общую сумму 102760448 байт.

Задача состоит в том, чтобы перенести первые 98 МБ (блоки 200704), поэтому перед ним есть пробел в 2 МБ (4096 блоков). Для этого на месте требуется, чтобы ничто не записывалось в сектор, который не был прочитан. Один из способов добиться этого – ввести буфер:

$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 | dd of=/dev/sdj2 seek=4096 

Ожидается, что mbuffer будет хранить 4096 блоков, прежде чем передавать что-либо писателю, тем самым гарантируя, что ничто не будет записано в область, которая не была прочитана, и что писатель отстает от читателя на размер буфера. Буфер должен позволять читателю и писателю работать как можно быстрее в пределах этих констриантов.

Однако, похоже, он не работает надежно. Я пытался использовать реальные устройства, но на них никогда не работает, тогда как эксперименты с файлом работали на моем 64-битном поле, но не на моем 32-битном поле.

Во-первых, некоторые приготовления:

 $ dd if=/dev/sdj2 count=200704 | md5sum 0f0727f6644dac7a6ec60ea98ffc6da9 $ dd if=/dev/sdj2 count=200704 of=testfile 

Это не работает:

 $ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=/dev/sdj2 seek=4096 summary: 98.0 MiByte in 4.4sec - average of 22.0 MiB/s md5 hash: 3cbf1ca59a250d19573285458e320ade 

Это работает на 64-битной системе, но не на 32-битной системе:

 $ dd if=testfile count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=testfile seek=4096 conv=notrunc summary: 98.0 MiByte in 0.9sec - average of 111 MiB/s md5 hash: 0f0727f6644dac7a6ec60ea98ffc6da9 

Как это можно сделать надежно?


заметки

Я прочитал другие вопросы о буферизации и посмотрел на pv , buffer и mbuffer . Я мог бы заставить последнего работать с требуемым размером буфера.

Использование промежуточного хранилища является очевидным решением проблемы, которая всегда работает, но это нецелесообразно, когда достаточная запасная емкость недоступна.

Испытательные платформы, на которых работает Arch Linux с версией mbuffer 20140302.

  • Перезаписать часть файла без модификации в немодифицированный контент
  • Жесткий диск исчез
  • Поддерживает ipod с помощью dd, как получить все треки за один раз с gnupod?
  • Как сделать DD через сеть на внешний HD?
  • Предельные данные по трубе в байтах
  • Записать сжатый файл .img в файл устройства
  • Команда unetbootin и dd не работает при загрузке usb, застрявшей на черном экране с подчеркиванием
  • Перенос содержимого блочного устройства LVM, обеспечивающего согласованность - моментальный снимок LVM?
  • 3 Solutions collect form web for “Как можно использовать `dd` для блоков данных с правом сдвига?”

    Без буфера вы могли бы вернуться назад, по одному блоку за раз.

     for i in $(seq 100 -1 0) do dd if=/dev/thing of=/dev/thing \ bs=1M skip=$i seek=$(($i+2)) count=1 done 

    Обратите внимание, что этот пример опасен из-за отсутствия проверки ошибок.

    Это также медленно из-за количества вызовов dd . Если у вас есть запасная память, вы можете использовать более крупный размер.

    С буфером, остерегайтесь ловушек . Недостаточно гарантировать 100% предварительную обработку. То, что вам нужно, является минимальным заполнением на протяжении всего процесса. Буфер никогда не должен опускаться ниже 2M потому что в противном случае вы снова перезапишите данные, которые еще не читаются.

    Поэтому, хотя теоретически вы можете обойтись без какого-либо буфера и просто цепочки dd :

     dd if=/dev/thing bs=1M | \ dd bs=1M iflag=fullblock | \ dd bs=1M iflag=fullblock | \ dd of=/dev/thing bs=1M seek=2 

    На практике это не работает надежно, потому что нет гарантии, что первый dd сумеет продолжать чтение данных, а последний dd2M «буфера» между ними) уже пишет.

    Вы можете значительно увеличить свои шансы, сделав промежуточный буфер значительно большим, но даже в этом случае он не является надежным.

    К сожалению, я не знаю хорошей буферной программы с минимальным свойством заполнения. Вам нужен тот, который останавливает вывод, если в буфере меньше вашего запаса прочности.

    Надежное решение требует, чтобы вы гарантировали, что ничего не записывается в область, которая может быть не прочитана, и единственный реальный способ добиться этого – выполнить копию в обратном направлении.

    Инструмент ddrescue может работать в обратном направлении, но он отказывается работать с одинаковым входом и выходом. Однако это можно обмануть, дублируя узел устройства.

    Я провел несколько быстрых экспериментов и, похоже, работает. Командная строка:

     $ ddrescue -f -R -s 200704s -o 4096s /dev/sdj11 /dev/sdj11_copy 

    Аргументы:

    • -f требуется, чтобы заставить его записывать на существующее устройство вывода
    • -R говорит, что он работает в обратном направлении
    • -s сообщает, сколько копий ввода (я использовал суффикс s чтобы указать количество секторов)
    • -o сообщает, что он должен искать вперед в устройстве вывода перед записью (указанный в секторах снова с суффиксом s )
    • /dev/sdj11 является блочным устройством для чтения
    • /dev/sdj11_copy – это блок-устройство для записи

    Я создал /dev/sdj11_copy с mknod для соответствия параметрам /dev/sdj11 .

    Я сделал только очень быстрые тесты, но, похоже, работает нормально, чтобы скопировать исходное устройство. Он не работает над файлом (я не мог обмануть его в том, чтобы выходить за рамки того же файла)

    Это не отвечает на мой первоначальный вопрос, который спрашивает, как добиться этого с помощью dd но я думаю, прочитав другие ответы, ответ на этот вопрос заключается в том, что dd не может этого сделать.

    Вы читаете 4096 блоков, а затем записываете эти 4096 блоков в следующие 4096 блоков диска, тем самым перезаписывая второй 4096 блоков, прежде чем их можно будет прочитать. Вам нужно прочитать 8129 блоков, чтобы получить эти секунды 4096, прежде чем начинать писать, а затем вам нужно написать только 4096 блоков, прежде чем читать следующие 4096.

    Вы не указали, что это за файловая система. Если это ext [234], и у вас есть последняя версия e2fsprogs, вы можете использовать e2image -ra -O 512 /dev/sdj2 . Это также имеет дополнительное преимущество, чтобы быть достаточно умным, чтобы пропустить свободное пространство в томе.

    Linux и Unix - лучшая ОС в мире.