Документация по ОС FreeBSD Понедельник, 20.05.2024, 09:07
Приветствую Вас Гость | RSS
Меню сайта

Категории каталога
Мои статьи [0]
Установка и настройка [281]
X Window [25]
Man pages [30]
Ports & Packages [26]
cvs [18]
Multimedia [20]
Нововсти в мире Unix [0]
RFC [4]
RFC (Request for Comments, Запрос на комментарии) - серия документов, публикуемая сообществом исследователей и разработчиков, руководствующихся практическими интересами, в которой описывается набор протоколов и обобщается опыт функционирования Интернет.
Безопасность [52]
Работа с железом [58]
Книги по FreeBSD [17]
Сеть [505]
Программирование [40]
FireWall [58]
Темы экзамена BSDA [14]
Официальные темы экзамена BSDA, включая подробноые описания и советы по обучению.

Главная » Статьи » Установка и настройка

Восстановление ZFS-пула с помощью подручных средств. Часть 2 [2011]

2.6. Решение грубой силой

Для того, что бы заставить ZFS откатиться к предыдущему состоянию, было необходимо стереть Uberblock последней удачной транзакции (а это была 253277 транзакция). Но прежде, немного переделав предыдущий скрипт, я получил скрипт извлекающий номера транзакций из всех Uberbock'ов всех дампов. Другой вариант поиска необходимого Uberblock'а - найти его по значению в дампе (253277 = 03DD5Dh).

Примечание.
Данный скрипт будет работать только на пулах созданных на узлах с big-endian архитектурой (x86, etc). Для little-endian архитектур необходимо в функции преобразования массива в число убрать цикл, инвертирующий массив.

Примечание.
На платформе i386, функция преобразования массива в число, при больших номерах транзакций, может работать с ошибками. Это вызвано тем, что для представления номера транзакции используется 64-битное число, а expr(1) работает со стандартными типами и может произойти целочисленное переполнение. Для 64-битной платформы (AMD64) такого ограничения быть не должно (но не проверялось).

Листинг 2.6.1. Скрипт извлекающий номера транзакций Uberblock'ов
#!/bin/sh

DISKS="ad2 ad4 ad6"
LABELS="0 1 2 3"

FIELD_OFF=16
FIELD_LEN=8

arr2int()
{
 arr=""
 res=0

 # Invert octet order
 for oct in $1; do
 arr="$oct $arr"
 done

 # Convert
 for oct in $arr; do
 oct=`printf "%d" 0x$oct`
 res=`expr -e $res \* 256 + $oct`
 done

 echo $res
}

fin=`expr 256 \* 1024`
prev=""
for DISK in $DISKS; do
 for L in $LABELS; do
 fdump="$DISK-label$L.dump"
 # First block pos
 off=`expr 128 \* 1024 + $FIELD_OFF`
 n=0
 while [ $off -lt $fin ]; do
 # Get octets array
 str=`od -t xC -A n -v -j $off -N $FIELD_LEN $fdump`
 str=`echo $str | sed 's/^ *\([^ ].*[^ ]\) *$/\1/'`
 # Convert to integer
 txg=`arr2int "$str"`
 printf "txg %10u disk %s label %s n %3u\n" $txg $DISK $L $n
 off=`expr $off + 1024`
 n=`expr $n + 1`
 done
 done
done

После запуска скрипта и перенаправления вывода в файл, получил список из 1536 записей (3 диска с 4 метками по 128 блоков в каждой). Далее сортируем его по номеру транзакции и определяем наибольший.

Листинг 2.6.2. Поиск Uberblock'а с наибольшим номером
~# ./extract-ub-txg.sh > txg.lst
~# sort txg.lst | tail -n 10
txg 253276 disk ad6 label 2 n 92
txg 253276 disk ad6 label 3 n 92
txg 253277 disk ad2 label 0 n 93
txg 253277 disk ad2 label 1 n 93
txg 253277 disk ad2 label 2 n 93
txg 253277 disk ad2 label 3 n 93
txg 253277 disk ad6 label 0 n 93
txg 253277 disk ad6 label 1 n 93
txg 253277 disk ad6 label 2 n 93
txg 253277 disk ad6 label 3 n 93

Ага. Транзакция 253277 есть только на ad2 и ad4 видимо на ней ad4 и стало плохо. Теперь определим, на каких дисках есть запись о предыдущей транзакции и с каким номером были записаны метки на дисках.

Листинг 2.6.3. Определение номеров транзакций меток
~# zdb -l /dev/ad2 | grep "txg"
 txg=253277
 txg=253277
 txg=253277
 txg=253277
~# zdb -l /dev/ad4 | grep "txg"
 txg=247242
 txg=247242
 txg=247242
 txg=247242
~# zdb -l /dev/ad6 | grep "txg"
 txg=253277
 txg=253277
 txg=253277
 txg=253277

Листинг 2.6.4. Поиск Uberblock'ов последней и предпоследней транзакций
~# grep "25327[67]" txg.lst | sort
txg 253276 disk ad2 label 0 n 92
txg 253276 disk ad2 label 1 n 92
txg 253276 disk ad2 label 2 n 92
txg 253276 disk ad2 label 3 n 92
txg 253276 disk ad4 label 0 n 92
txg 253276 disk ad4 label 1 n 92
txg 253276 disk ad4 label 2 n 92
txg 253276 disk ad4 label 3 n 92
txg 253276 disk ad6 label 0 n 92
txg 253276 disk ad6 label 1 n 92
txg 253276 disk ad6 label 2 n 92
txg 253276 disk ad6 label 3 n 92
txg 253277 disk ad2 label 0 n 93
txg 253277 disk ad2 label 1 n 93
txg 253277 disk ad2 label 2 n 93
txg 253277 disk ad2 label 3 n 93
txg 253277 disk ad6 label 0 n 93
txg 253277 disk ad6 label 1 n 93
txg 253277 disk ad6 label 2 n 93
txg 253277 disk ad6 label 3 n 93

Итак, текущий активный Uberblock располагается в 93 позиции массива Uberblock'ов на дисках ad2 и ad6. Uberblock предыдущей транзакции расположен в 92 позиции на всех дисках. Остаётся рассчитать смещение в дампе 93 позиции массива: 128 + 93 = 221 (Кб). Проверим расчёт, найдя блок по номеру транзакции: 253277 = 03dd5dh, с учётом порядка байт, нужно найти последовательность: 5d dd 03 00.

Листинг 2.6.5. Поиск Uberblock'а по номеру транзакции
~# od -t xC -A x ad2-label0.dump | grep -B 1 "5d dd 03 00" | head -n 2
0037400 0c b1 ba 00 00 00 00 00 0e 00 00 00 00 00 00 00
0037410 5d dd 03 00 00 00 00 00 71 78 02 5c 2e cc 05 2d

Искомая последовательность найдена по смещению 037410h, блок начинается по смещению 037400h, т.к. поле txg расположено по смещению 10h = 16 байт от начала блока. Переведём в килобайты: 037400h / 400h = ddh = 221 - предыдущий расчёт смещения был сделан верно. Остаётся затереть текущие активные блоки и записать метки назад на диск. Но перед этим стоит сохранить оригинальные метки.

Листинг 2.6.6. Удаление Uberblock'ов
~# mkdir orig
~# cp ad*.dump ./orig/
~# dd if=/dev/zero of=ad2-label0.dump bs=1024 count=1 seek=221 conv=notrunc
1+0 records in
1+0 records out
1024 bytes transferred in 0.000078 secs (13134457 bytes/sec)
~# dd if=/dev/zero of=ad2-label1.dump bs=1024 count=1 seek=221 conv=notrunc
...
~# dd if=/dev/zero of=ad2-label2.dump bs=1024 count=1 seek=221 conv=notrunc
...
~# dd if=/dev/zero of=ad2-label3.dump bs=1024 count=1 seek=221 conv=notrunc
...
~# dd if=/dev/zero of=ad6-label0.dump bs=1024 count=1 seek=221 conv=notrunc
...
~# dd if=/dev/zero of=ad6-label1.dump bs=1024 count=1 seek=221 conv=notrunc
...
~# dd if=/dev/zero of=ad6-label2.dump bs=1024 count=1 seek=221 conv=notrunc
...
~# dd if=/dev/zero of=ad6-label3.dump bs=1024 count=1 seek=221 conv=notrunc
...

Было бы неплохо проверить, те ли блоки были затёрты.

Листинг 2.6.7. Проверка содержимого блоков
~# od -t xC -A x -v ad2-label0.dump | grep -A 1 "^0037410"
0037410 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0037420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Так, блоки затёрты - остаётся вернуть метки на диск.

Внимание!!!
Я экспериментировал с рабочими дисками потому, что информация, хранимая на них не представляла особой ценности. Если потеря информации недопустима, то предварительно выполняют полное копирование содержимого дисков на другие диски, аналогичной модели. И все операции выполняют на изготовленной копии. В случае недопустимости потери информации, работа (в особенности запись) с рабочими дисками недопустима! И вообще, существуют целые организации, специализирующиеся на восстановлении данных - лучше обратиться к ним, если вы не являетесь экспертом по восстановлению информации с систем хранения, а информация вам дорога (например, как память).

Для записи меток обратно на диски я немного модифицировал первоначальный скрипт и запустил его.

Листинг 2.6.8. Скрипт записи меток на диски
#!/bin/sh

L0_OFF=0
L1_OFF=256
L2_OFF=1465137920
L3_OFF=1465138176

DISKS="ad2 ad4 ad6"

echo "Script disabled. Exit."
exit

for DISK in $DISKS; do
 echo "Write labels to: $DISK"
 l=0
 for OFF in $L0_OFF $L1_OFF $L2_OFF $L3_OFF; do
 fdump="$DISK-label$l.dump"
 echo " Label: $l (in: $fdump, offset: $OFF)"

 # Writing
 dd if="$fdump" of="/dev/$DISK" bs=1024 count=256 seek=$OFF 2> /dev/null

 l=`expr $l + 1`
 done
done

Скрестив пальцы, импортирую пул в режиме только для чтения.

Листинг 2.6.9. Импорт пула в режиме только чтение
~# zpool import -o ro storage

И-и-и-и, о чудо! Пул импортировался и чувствует себя нормально.

Листинг 2.6.10. Состояние пула после импорта
~# zpool status
 pool: storage
 state: ONLINE
status: The pool is formatted using an older on-disk format. The pool can
 still be used, but some features are unavailable.
action: Upgrade the pool using 'zpool upgrade'. Once this is done, the
 pool will no longer be accessible on older software versions.
 scrub: resilver completed after 0h0m with 0 errors on Wed Dec 28 16:08:41 2010
config:

 NAME STATE READ WRITE CKSUM
 storage ONLINE 0 0 0
 raidz1 ONLINE 0 0 0
 ad2 ONLINE 0 0 0
 ad4 ONLINE 0 0 0 23K resilvered
 ad6 ONLINE 0 0 0

errors: No known data errors

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

Мораль

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

Список литературы



Источник: http://www.lissyara.su/articles/freebsd/file_system/zfs_recovery/
Категория: Установка и настройка | Добавил: oleg (05.02.2011)
Просмотров: 988 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа

Beastie

Друзья сайта

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
links

Copyright MyCorp © 2024