Як можна використовувати `dd` для блокування даних з правою зміною?


10

Розглянемо блок простого блоку на 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. Я міг змусити останнього працювати лише з необхідним розміром буфера.

Використання інтерметіатів для зберігання є очевидним рішенням проблеми, яка завжди працює, але це не практично, коли недостатня запасна ємність недоступна.

Тестові платформи під управлінням Linux Linux з mbufferверсією 20140302.


Я не думаю, що це вирішить проблему, але з цікавості навіщо mbufferвзагалі використовувати ? Чому б замість цього не змусити за один раз ddпрочитати весь вміст блокового пристрою dd bs=102760448? Звичайно, так чи інакше він буферизований в оперативній пам'яті.
Селада

@Celada - приклад 100MB був лише прикладом. Наприклад, читання 1 ТБ за один раз не було б такою хорошою ідеєю.
starfry

2
Ах, я розумію зараз, дякую. Фактично mbufferслід змусити другий ddвідставати на першому, і вам потрібно лише достатня оперативна пам’ять, щоб захистити розмір зсуву. Дуже погано ddне підтримує читання та запис блоків у зворотному порядку, оскільки це усуне проблему!
Селада

Ви не перерахували, як ви обчислили другий md5sum
psusi

@psusi, другий md5 виводиться mbuffer (його -Hаргумент дозволяє цю функцію).
starfry

Відповіді:


2

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

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"буфером" між ними) вже пише.

Ви можете значно збільшити свої шанси, зробивши між ними буфер значно більшим, але навіть це не надійно.

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


Я прийняв це, оскільки він відповідає на початкове запитання, демонструючи, як ddможна його використовувати. Я думаю, однак, що справжнє рішення - це не використовувати, ddа замість цього вибрати щось, що призначене для запуску назад ddrescue. Я описав спосіб зробити це у відповіді.
starfry

1
@starfry: звичайно, програма, яка просто робить це, буде приємним рішенням. Однак я тут зовсім не впевнений ddrescue. Не в тому випадку, якщо він розраховує працювати на різних пристроях, і вам доведеться обдурити його у прийнятті ваших аргументів. Він може не мати внутрішньої властивості "мінімальна заповнення буфера" (оскільки для різних пристроїв це не потрібно), тому знову може пошкодити ваші дані. У вихідному коді вам доведеться перевірити, чи дійсно він призначений для вашого випадку використання.
frostschutz

1

Ви читаєте 4096 блоків, а потім записуєте ці 4096 блоки на наступні 4096 блоки диска, таким чином, перезаписуючи другі 4096 блоки, перш ніж їх можна буде прочитати. Вам потрібно прочитати 8129 блоків, щоб отримати ці 4096 перед тим, як почати писати, а потім потрібно лише написати 4096 блоків, перш ніж читати наступні 4096.

Ви не згадали, що це за файлова система. Якщо це ext [234], і у вас є остання версія e2fsprogs, ви можете використовувати e2image -ra -O 512 /dev/sdj2. Це також має додаткову перевагу - бути досить розумним, щоб пропустити вільний простір в обсязі.


Це має сенс, читаючи його, і я буду ще раз поглянути на це. Але це не пояснює, чому він працював на тестовому файлі.
starfry

Що стосується файлової системи, ви посилаєтесь на файлову систему, що містить мій тестовий файл? Ось, ext4але для блокування копіювання пристрою будь-яка файлова система повинна бути неактуальною.
starfry

@starfry, єдиний спосіб, який я знаю, щоб зробити це загальним способом, - це використовувати алгоритм, запропонований Еммануїлом (робота від кінця), що і робить gparted.
psusi

повторно розмір блоку, я спробував більші блоки (я повинен був це записати у питанні). Я виявив, що не став більш надійним навіть буфер 64K. Надійне рішення - бігти назад, те, що ddне робить.
starfry

1

Надійне рішення вимагає, щоб ви гарантували, що нічого не записується в область, яка, можливо, не була прочитана, і єдиний реальний спосіб досягти цього - виконувати копію в зворотному напрямку.

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не в змозі.


Що станеться, якщо ddrescueв цьому сценарії виявиться поганий блок? Якщо він переходить на іншу область диска (щоб уникнути поганих блоків) і продовжує копіювати звідти, він знову перезаписає ще не скопійовані частини ваших даних. Якщо він не сподівається працювати з тим же пристроєм, він не має підстав вживати спеціальних заходів для запобігання різних можливих випадків корупції даних.
frostschutz

Я погоджуюсь, що це потенційна проблема, але я не розглядав крайові випадки, оскільки мені вдалося використати це, щоб зробити те, що мені потрібно. Є ddrescueваріанти обмежити його спроби відновити погані дані, але я не розглядав їх використання.
starfry

Той факт, що він відмовляється працювати, якщо вхід і вихід однакові, ймовірно, хороший показник того, що це не безпечно.
psusi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.