|
|
www.lissyara.su
—> статьи
—> FreeBSD
—> Файловая система
—> Восстановление ZFS
Восстановление ZFS-пула с помощью подручных средств
Автор: BlackCat.
Оглавление
Введение
1. Предыстория
2. Восстановление
2.1. Рекогносцировка местности
2.2. Некоторые сведения об устройстве ZFS
2.3. Детальное обследование пациента
2.4. Тяжёлая артиллерия
2.5. Поиск ответов в коде реализации
2.6. Решение грубой силой
Год спустя
Мораль
Список литературы
Фарш нельзя провернуть назад.
Слоган радиопередачи
"Литрофарш".
Введение
Представленный материал ни в коем случае не является инструкцией по восстановлению или чем-то похожим на инструкцию. Это просто рассказ о решении одной не тривиальной, для меня, задачи. И доказательство того факта, что ZFS вполне может быть восстановлена даже когда её драйвер утверждает, что пора доставать резервную копию т.к. все данные превратились в фарш, а фарш... О том, что нельзя сделать с фаршем читайте в эпиграфе. Текст написан в неформальном стиле, что бы подчеркнуть антинаучность представленного материала.
1. Предыстория
Был RAID-Z-пул собранный из трёх дисков по 1.5 Тб фирмы X, модели Y. Работал он работал, и изредка стали появляться в логах сообщения о том, что произошла ошибка чтения или ошибка записи на один из дисков пула. ZFS, ругаясь в логи на ошибки контрольных сумм, отлично отрабатывала такие моменты и пул продолжал нормально функционировать со статусом "ONLINE". Ошибки повторялись, но были не систематичными: различные диски, различные сектора, различное время. Назвав ошибки идиопатическими (неизвестной природы) решил, что обязательно разберусь с ними, но не сейчас. Эпик фейл подкрался незаметно, но всё же наступил. В один, не самый удачный момент, после перезагрузки, файловая система не cмонтировалась.
Листинг 1.1. Развалившийся пул с почти отказавшим диском
~# zpool import
pool: storage
id: 15607890160243212464
state: FAULTED
status: The pool metadata is corrupted.
action: The pool cannot be imported due to damaged devices or data.
The pool may be active on another system, but can be imported using
the '-f' flag.
see: http://www.sun.com/msg/ZFS-8000-72
config:
storage FAULTED corrupted data
raidz1 ONLINE
ad2 ONLINE
ad4 OFFLINE
ad6 ONLINE
|
При попытке импорта пула, zpool(8) вообще сваливался в кору.
Листинг 1.2. Падение zpool(8) в кору
~# zpool import -o ro storage
internal error: Illegal byte sequence
Abort (core dumped)
|
В логах стабильно появлялись два сообщения, свидетельствующие о том, что некоторые сектора на ad4 приказали долго жить. Как выяснилось далее, в этих секторах начинались важные для ZFS структуры данных, но первые несколько килобайт этой структуры, удачным образом, не использовались и были помечены в спецификации, как "Blank space" (пустое место).
Примечание.
Здесь и далее под килобайтом понимается 1024 байта, размер сектора так же стандартный, т.е. 512 байт.
Листинг 1.3. Сбойные сектора
ad4: FAILURE - READ_DMA48 status=51<...> error=40<UNCORRECT...> LBA=2930275840
ad4: FAILURE - READ_DMA48 status=51<...> error=40<UNCORRECT...> LBA=2930276352
|
Попробовал прочитать эти сектора и убедился в том, что они работать не будут.
Листинг 1.4. Чтение сбойных секторов "в ручную"
~# dd if=/dev/ad4 of=/dev/null bs=512 skip=2930275840
dd: /dev/ad4: Input/output error
0+0 records in
0+0 records out
0 bytes transferred in 2.777067 secs (0 bytes/sec)
|
Подключил диск такой же модели и в несколько приёмов (обходя сбойные сектора) скопировал на него содержимое глючившего диска. После чего поставил новый диск вместо глючного и попытался импортировать пул. Но, к моему разочарованию, пул отказался импортироваться и с новым диском. zpool(8) продолжал падать в кору.
Листинг 1.5. Развалившийся пул, после замены диска
~# zpool import
pool: storage
id: 15607890160243212464
state: FAULTED
status: The pool metadata is corrupted.
action: The pool cannot be imported due to damaged devices or data.
The pool may be active on another system, but can be imported using
the '-f' flag.
see: http://www.sun.com/msg/ZFS-8000-72
config:
storage FAULTED corrupted data
raidz1 ONLINE
ad2 ONLINE
ad4 ONLINE
ad6 ONLINE
|
Официальная документация утверждала то же, что и состояние пула - пора доставать резервную копию. Копия была, но последний раз она выполнялась чуть меньше года назад и была, мягко говоря, "неактуальной". Можно было восстановить данные из этой копии, всё лучше, чем ничего, да и не столь важны они были. Но мысль о том, что данные ещё существуют - их только необходимо извлечь не давала покоя.
2. Восстановление
2.1. Рекогносцировка местности
Внутреннее устройство ZFS я знал плохо - пришлось изучать его на форсаже, с прицелом на возможность восстановления данных. После недолгих поисков нагуглил[1] сообщение некоего Nathan Hand, который утверждал, что смог восстановить работоспособность пула. Так же в сообщении обнаружилась ссылка на черновой вариант спецификации[2] ZFS. Настроение стало улучшаться.
2.2. Некоторые сведения об устройстве ZFS
Тем, кто знаком с устройством ZFS этот раздел будет бесполезен, тем, кто не знаком - этот раздел будет даже вреден, лучше читать оригинальную спецификацию. Но, по-традиции, несколько слов об устройстве ZFS, как понял его я.
Структура данных, с которой начинается разбор бинарного месива диска перед тем как это месиво станет навороченной файловой системой, называется метка (англ. Label). На диске хранится несколько меток в строго определённых позициях.
Схема 2.2.1. Расположение меток на диске
+----+----+--------------------+----+----+
| L0 | L1 | | L2 | L3 |
+----+----+--------------------+----+----+
|
L0, L1, L2, L3 - метки ZFS. L0, L1 - располагаются друг за другом без пропусков в начале диска (с нулевого смещения). L2, L3 - располагаются в конце диска, но не обязательно в самых последних секторах, после них может оставаться свободное место (скорее всего из-за выравнивания на 128 Кб). Пространство между L1 и L2 занято вспомогательными структурами и самими данными, но их позиции строго не определены. Метки на одном диске должны быть строго одинаковыми. О том, почему выбрано такое количество меток и каким образом они обновляются хорошо написано в документации[2].
Структура метки достаточно проста, она состоит из 8Кб пустого пространства (англ. Blank Space), 8Кб загрузочного заголовка (англ. Boot Header), 112Кб конфигурационных данных в формате имя - значение (англ. Name/Value Pair List) и 128Кб массива структур Uberblock. Итого получается 256Кб на одну метку.
Схема 2.2.2. Структура метки
Blank Boot Name/Value Uberblock
Space Header Pair List Array
+-------+--------+----------------+---------------------------------+
| | | | | | | | | | | | | | | ... | | |
+-------+--------+----------------+---------------------------------+
0 8K 16K 128K 256K
|
Список имя-значение, содержит следующие конфигурационные данные (перечислены самые интересные, на мой взгляд):
- version - версия формата хранения;
- name - имя пула;
- state - состояние пула (активен/экспортирован/удалён);
- txg - номер транзакции в которой выполнялась запись (будет описан далее);
- pool_guid - уникальный идентификатор пула;
- guid - уникальный идентификатор виртуального устройства;
- vdev_tree - дерево, описывающее всю конфигурацию входящих в пул виртуальных устройств, само дерево состоит из пар имя-значение, основные поля описывающие отдельное устройство:
- type - тип устройства (файл/блочное устройство/зеркало/raidz/корень);
- path - имя устройства (только для файлов и блочных устройств);
- guid - уникальный идентификатор описываемого виртуального устройства;
- children - массив подчинённых виртуальных устройств.
Более подробное описание самих данных и ссылки на формат их хранения доступны в спецификации.
Примечание.
Следует отметить, что ZFS активно оперирует таким понятием, как виртуальное устройство (англ. vdev), под которым может пониматься, как вполне реальный диск, так и абсолютно абстрактный RAID-Z массив или корень иерархии устройств.
Uberblock (перевода не придумал) по своей природе похож на Superblock UFS - он является началом всей структуры данных на диске. Почему используется целый массив блоков вместо одного? Всё просто: ZFS никогда не пишет данные поверх уже существующих, вместо этого она записывает новую структуру в новую позицию, и только потом допускает возможность модификации уже имеющихся данных (их перезапись). При чтении структуры диска (напр. после перезагрузки) просто находится запись сделанная последней и используется, остальные записи считаются неактуальными. Сам Uberblock в начале содержит пять 64-битных полей:
- ub_magic - "магическое число" идентифицирующее (сигнатура) блок;
- ub_version - версия формата хранения;
- ub_txg - номер транзакции в которой записана данная структура;
- ub_guid_sum - сумма идентификаторов устройств;
- ub_timestamp - UTC метка времени.
Далее следуют указатели на подчинённые структуры. Суммарный объём структуры равен 1Кб. С учётом того, что массив имеет объём 128Кб получаем, что в каждой метке может храниться 128 Uberblock'ов, созданных в разное время.
"Магическое число" всегда равно 0x00bab10c (oo-ba-block) на диск данное значение будет записано следующей последовательностью байт.
Таблица 2.2.1. Запись "Магического числа"
+----------------+-------------------------+
| Edians | Bytes |
+----------------+-------------------------+
| Little (x86) | 0c b1 ba 00 00 00 00 00 |
| Big (Sparc) | 00 00 00 00 00 ba b1 0c |
+----------------+-------------------------+
|
Особого внимания заслуживает поле транзакция, в котором хранится номер транзакции, по завершении которой и был записан данный Uberblock. Так же, как было отмечено ранее, номер транзакции отдельно указывается в метке. На основании этого номера и принимается решение, какой Uberblock считается активными. Активным считается Uberblock с максимальным номером транзакции, при этом номер транзакции блока должен быть больше и равен номеру транзакции метки. Если это условие не выполняется, то производится поиск блока с меньшим номером. Т.о. если при выполнении транзакции произошла ошибка и Uberblock записан не был, то ZFS сможет корректно откатиться к предыдущей транзакции.
Для просмотра содержимого меток диска используется опция "-l" утилиты zdb(8).
Дальше начинаются дебри из структур, описывающих расположение блоков на диске. Кому интересно, тот может ознакомиться с ними в документации[2].
2.3. Детальное обследование пациента
Начать было решено с простейших манипуляций - проверить читаемость и корректность меток, с помощью zdb(8).
Листинг 2.3.1. Чтение меток с дисков (показано только начало дампа)
~# zdb -l /dev/ad2
--------------------------------------------
LABEL 0
--------------------------------------------
version=14
name='storage'
state=0
txg=253277
pool_guid=15607890160243212464
...
~# zdb -l /dev/ad4
--------------------------------------------
LABEL 0
--------------------------------------------
version=14
name='storage'
state=0
txg=247242
pool_guid=15607890160243212464
...
~# zdb -l /dev/ad6
--------------------------------------------
LABEL 0
--------------------------------------------
version=14
name='storage'
state=0
txg=253277
pool_guid=15607890160243212464
...
|
Никакого криминала метки считались - придётся вводить в действие тяжёлую артиллерию.
2.4. Тяжёлая артиллерия
Для того, что бы было удобнее копаться в бинарном содержимом меток их необходимо было скопировать с дисков в отдельные файлы. Для этого нужно знать начала меток и их размер на диске. С размером вопросов не было - размер меток постоянен и равен 256Кб. Смещения L0 и L1 равны 0 и 256Кб соответственно. Оставалось выяснить смещения L2 и L3. Объём диска равен 1465138584Кб, вычитая размер метки, я должен был получить смещение метки L3: 1465138328Кб. Но не тут то было. Сделав дамп 256Кб от полученного смещения я решил его проверить, найдя смещение первого Uberblock'а от начала дампа. Это должно было быть ровно 128Кб или 020000h. Uberblock легко определить в куче байт по "Магическому числу", с которого он начинается, но необходимо делать поправку на порядок байт в записи числа.
Листинг 2.4.1. Неправильный выбор смещения
~# dd if=/dev/ad2 of=tmp.dump bs=1024 count=256 skip=1465138328
256+0 records in
256+0 records out
262144 bytes transferred in 0.057129 secs (4588621 bytes/sec)
~# od -t xC -A x tmp.dump | grep "0c b1 ba 00" | head -n 1
0000000 0c b1 ba 00 00 00 00 00 0e 00 00 00 00 00 00 00
|
Промазал. Первый Uberblock в полученном дампе располагался на нулевом смещении, а это значит, что ошибка составляет минимум 128Кб. Т.к. первый Uberblock должен располагаться на смещении 128Кб от начала метки, а в дампе уже на нулевом смещении я видел один из блоков. Для определения корректного смещения было необходимо определить, сколько Uberbock'ов попало в дамп и сместиться на соответствующее количество блоков + 128Кб.
Листинг 2.4.2. Определение количества Uberblock'ов, попавших в дамп
~# dd if=/dev/ad2 of=tmp.dump bs=1024 count=256 skip=1465138328
256+0 records in
256+0 records out
262144 bytes transferred in 0.057163 secs (4585903 bytes/sec)
~# od -t xC -A x tmp.dump | grep "0c b1 ba 00" | wc -l
104
|
В дампе 104 блока, должно быть 128 - нам надо сместиться влево (к младшим адресам) на: (128 - 104) + 128 = 152 (Кб). Новое смещение: 1465138328 - 152 = 1465138176 (Кб). Делаем дамп и проверяем количество блоков и смещение первого из них.
Листинг 2.4.3. Проверка нового смещения
~# dd if=/dev/ad2 of=tmp.dump bs=1024 count=256 skip=1465138176
256+0 records in
256+0 records out
262144 bytes transferred in 0.057357 secs (4570387 bytes/sec)
~# od -t xC -A x tmp.dump | grep "0c b1 ba 00" | head -n 1
0020000 0c b1 ba 00 00 00 00 00 0e 00 00 00 00 00 00 00
~# od -t xC -A x tmp.dump | grep "0c b1 ba 00" | wc -l
128
|
Ага, угадал. Смещение L2 получить элементарно - необходимо вычесть 256Кб из полученного смещения L3: 1465138176 - 256 = 1465137920 (Кб). Получилась небольшая таблица смещений. Т.к. диски одинаковой модели, то и смещения для них будут одинаковыми.
Таблица 2.4.1. Смещения меток
+----+-------------+
| L# | Offset (Kb) |
+----+-------------+
| L0 | 0 |
| L1 | 256 |
| L2 | 1465137920 |
| L3 | 1465138176 |
+----+-------------+
|
Т.к. рутинную работу лучше выполняет машина, я набросал простенький скрипт для дампа всех меток в отдельные файлы.
Листинг 2.4.4. Скрипт для дампа
#!/bin/sh
L0_OFF=0
L1_OFF=256
L2_OFF=1465137920
L3_OFF=1465138176
DISKS="ad2 ad4 ad6"
for DISK in $DISKS; do
echo "Dump labels from: $DISK"
l=0
for OFF in $L0_OFF $L1_OFF $L2_OFF $L3_OFF; do
fdump="$DISK-label$l.dump"
echo " Label: $l (out: $fdump, offset: $OFF)"
# Create output file
touch "$fdump"
# Dumping
dd if="/dev/$DISK" of="$fdump" bs=1024 count=256 skip=$OFF 2> /dev/null
l=`expr $l + 1`
done
done
|
После его выполнения метки были сохранены в файлы adN-labelX.dump (N - номера дисков: 2, 4, 6; X - номер метки: 0, 1, 2, 3). Разбираться стало немного удобнее.
Далее я начал сравнивать конфигурации, записанные в метках, но результата это не принесло - оставалось лезть в код реализации ZFS для того, что бы выяснить какие именно данные были повреждены.
2.5. Поиск ответов в коде реализации
Немного порывшись по коду zpool и libzfs, обнаружил следующие строки в libzfs_status.c, которые и устанавливают статус пула "The pool metadata is corrupted".
Листинг 2.5.1. Код определяющий состояние ZFS-пула
/*
* Corrupted pool metadata
*/
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
return (ZPOOL_STATUS_CORRUPT_POOL);
|
Проверяемые поля устанавливаются в модуле ядра - пришлось перебираться в ядро. После недолгих поисков был найден файл spa.c, ответственный за открытие/закрытие, а так же импорт пула. В данном файле было несколько участков кода, в которых поля устанавливались в интересующее состояние. Надо было как-то выяснить что именно не нравиться алгоритму импорта. Для этого насовал кучу отладочного вывода в модуль, пересобрал его и загрузил вместо стандартного, разрешив вывод отладочной информации. Теперь, в момент импорта пула, в логи сыпалось множество отладочной информации, показывающей ход выполнения алгоритма импорта/открытия пула. Среди прочего был найден код проверки активного Uberblock'а.
Листинг 2.5.2. Проверка активного Uberblock'а
/*
* If we weren't able to find a single valid uberblock, return failure.
*/
if (ub->ub_txg == 0) {
vdev_set_state(rvd, B_TRUE, VDEV_STATE_CANT_OPEN,
VDEV_AUX_CORRUPT_DATA);
|
Примечание.
У zpool(8) есть специальная недокументированная опция "-F", которая позволяет импортировать даже сбойный пул. Работать после этого он конечно не будет, но для отладки и восстановления данных опция полезная.
Добавив перед проверкой вывод номера транзакции активного блока, получил номер транзакции, которую ZFS считает последней удачной. Это была 253277 транзакция.
Немного порывшись в коде, пришёл к выводу, что ошибка где-то глубже чем неправильно записанная метка. Т.к. восстанавливать всю структуру блок за блоком в мои планы не входило (пул содержал несколько сотен гигабайт не такой уж и ценной информации), я решил прибегнуть к грубой силе - заставить ZFS откатиться к предыдущей транзакции.
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" - не наш метод. И вот пока бегут в обратную сторону часы, оставшиеся до завершения копирования я и решил записать эту небольшую историю.
Год спустя
Ещё весной задал на форуме вопрос о поддержке "отмотки" транзакций. И был направлен тов. Anon Y Mous на путь истинный, т.е. в последние (на тот момент) правки HEAD-ветки. Немного покопавшись в репозитории, нашёл нужную правку[3], в которой была добавлена поддержка той самой "отмотки" транзакций. Но это всё предисловие.
После обновления, в правке за номером 219089 [3], ZFS до версии 28, в zpool(8) появилась возможность откатываться на несколько транзакций назад при передаче параметра -F. Так что описанный в статье приём восстановления стал обычной рутинной задачей. За подробностями по ссылке на правку или в подсказку, выводимую zpool(8).
Мораль
А мораль проста и давно всем известна - даже самые отказоустойчивые технологии могут дать сбой, а поэтому, систематическое резервное копирование важных данных один из лучших способов чувствовать себя сухо и комфортно.
Список литературы
1. Need Help Invalidating Uberblock // http://mail.opensolaris.org/pipermail/zfs-discuss/2008-December/024427.html
2. ZFS On-Disk Specification // http://opensolaris.org/os/community/zfs/docs/ondiskformat0822.pdf
3. FreeBSD repo revision 219089 // http://svnweb.freebsd.org/base?view=revision&revision=219089
Ссылка на обсуждение: http://forum.lissyara.su/viewtopic.php?f=14&t=30532.
размещено: 2011-02-04,
последнее обновление: 2012-02-02,
автор: BlackCat
|
|
|
|
2014-07-27, lissyara
gmirror
Удалённое создание софтверного зеркала средствами gmirror, на диске разбитом с использованием gpart. Использование меток дисков для монтирования разделов.
2013-08-20, zentarim
Scan+Print server FreeBSD 9
Настройка сервера печати и сервера сканирования под управлением операционной системы FreebSD 9 для МФУ Canon PIXMA MP540
2011-11-20, BlackCat
Разъём на WiFi-карту
Делаем съёмной несъёмную антену на WiFi-карте путём установки ВЧ-разъёма
2011-09-14, manefesto
Настройка git+gitosis
Настройка системы контроля версия исходного кода в связке git+gitosis+ssh
2011-08-14, zentarim
Wi-FI роутер + DHCP + DNS
Настройка Wi-Fi роутера на Freebsd 8 + DNS сервер + DHCP сервер: чтобы Wi-Fi клиенты были в одной подсети с проводными, проводные и беспроводные клиенты получали адреса автоматически по DHCP, кэширующ
2011-06-15, -ZG-
Охранная система на FreeBSD+LPT
В этой статье описана попытка реализации простой охранной системы на базе FreeBSD с подключением к ней охранных устройтсв на LPT порт и видеорегистрацией.
2011-03-13, terminus
ng_nat
Описание работы ng_nat, практическое использование, достоинства и недостатки в сравнении с ipfw nat
2011-02-20, Капитан
Nagios+Digitemp
Статья описывает создание системы оповещения о превышении температуры в специальных помещениях на основе Nagios с использованием программы Digitemp.
2011-02-17, Le1
Zyxel Configuration
Скрипт для массового изменения конфига свичей Zyxel. Берет из файла iplist список ip-шек, заходит последовательно на каждый и выполняет комманды из файла commands, записывая происходящее в лог файл.
2011-02-16, fox
hast carp zfs ucarp cluster
HAST (Highly Available Storage), CARP, UCARP, ZFS, Cluster настройка и одаптация плюс личные размышления…
2011-02-04, BlackCat
Восстановление ZFS
История о том, как был восстановлен развалившийся RAIDZ ZFS-пул (перешедший в FAULTED) с помощью скотча и подручных средств. Или о том, какие приключения ожидают тех, кто не делает резервных копий.
2011-02-03, Капитан
1-Wire
Статья описывает самостоятельное изготовление контроллера DS9097 для съёма показаний с датчиков температуры DS1820 с помощью программы Digitemp.
2011-01-28, Капитан
Температура в серверной
Статья описывает построение системы наблюдения за температурой в помещении серверной с использованием программы Digitemp и выводом графиков в MRTG
2011-01-21, m4rkell
Syslog server
Как то буквально на днях, у нас завалилось, что то в еве) или не в еве не суть. Суть в том, что когда захотели снять логи с хостов esx обнаружили, что хранят эти негодяи логии только за последнии сутк
2011-01-07, lissyara
Canon/gphotofs
Монтирование цифровых фотоаппаратов Canon (PTP) как файловой системы, автоматизация этого процесса через события devd и внешние скрипты.
2010-12-13, Al
IPSec
Описание принципов работы IPSEC и способов аутентификации.
2010-12-07, manefesto
FreeBSD on flash
Было принято решении переехать на USB Flash и установить минимальный джентельменский набор для работы своего роутера. Делаем =)
2010-12-05, Fomalhaut
root ZFS, GPT
Инструкция по установке FreeBSD с использованием в качестве таблицы разделов GPT и в качестве основной файловой системы - ZFS
2010-09-05, Cancer
Настройка аудиоплеера на ximp3
Цели: Простенький аудиоплеер, для того что бы тетя продавец в магазине утром пришла нажала на кнопку Power и заиграла в зале музыка, так же был доступ по сети, общая шара куда можно заливать музыку, к
2010-08-31, Cancer
Установка и настройка OpenVPN
На днях появилась задача - объединить головной офис и 3 филиала в одну сеть через интернет посредством OpenVPN, чтобы люди могли подключаться через RDP к базам 1С на серверах.
2010-08-25, manefesto
freebsd lvm
Использование linux_lvm для работы с LVM разделами из-под FreeBSD. Проблемы которые возники при монтирование lvm раздела
2010-04-30, gonzo111
proftpd file auth"a
Proftpd - квоты и авторизация из файлов, без использования базы данных и/или системных пользователей
2010-04-22, lissyara
tw_cli
Пошаговая инструкция по восстановлению RAID на контроллере 3ware, из которого выпал один диск. Настройка мониторинга состояния рейда и отчётов о его состоянии на email.
2010-04-14, fox
MySQL Master+Master
MySQL (Master Master) and (Master Slave) Как настроить репликацию…
2010-03-09, terminus
DNS zones
Краткий ликбез про управление DNS зонами. Примеры проведения делегирования прямых и обратных DNS зон.
2010-03-09, aspera
Squid+AD (group access)
Настройка прокси сервера SQUID с автроризацией пользователей в AD. Разделение пользователей на группы
2010-03-02, BlackCat
Шлюз: Часть 4
Настройка дополнительных сервисов: синхронизация времени (OpenNTPD), клиент DynDNS.org.
2010-03-01, BlackCat
Шлюз: Часть 3
Настройка DHCP и DNS серверов для работы внутри частной сети, c поддержкой внутренних (частных зон) DNS, а так же интеграция DHCP и DNS сервисов.
2010-03-01, BlackCat
Шлюз: Часть 2
Конфигурация МСЭ pf для проброса портов с изменением порта назначения и без, а так же поддержки активного режима FTP и ограничения максимального размера сегмента
2010-03-01, BlackCat
Шлюз: Часть 1
Быстрая настройка шлюза/маршрутизатора с установлением PPPoE-соединения, поддержкой NAT и DNS-forwarding.
2010-02-23, Morty
darkstat
Простая считалка траффика, со встроенным веб-сервером. Очень маленькая, может делать отчеты трафика по хостам, портам, протоколам, а также строить графики
2010-01-23, gonzo111
squid+sams+sqstat
Пилим squid и sams - примеры конфигов с объяснениями. Установка SqStat.
2009-12-19, schizoid
mpd5 + radius + ng_car + Abills
Настройка pppoe-сервера с биллинговой системой Abills и шейпером ng_car
2009-11-16, lissyara
UFS->ZFS
Удалённая миграция с UFS на ZFS. Загрузка с раздела zfs. Настройка для работы с малым количеством памяти под архитектурой i386.
2009-11-13, gx_ua
fusefs-ntfs
Установка, настройка и использование fusefs-ntfs, драйвер NTFS, предназанченного для монтирования NTFS разделов под FreeBSD
2009-11-12, Morty
LiveCD
Создание собственного LiveCD с необходимыми вам изменениями, автоматизирование данного процесса, а так же вариант скоростной сборки СД.
2009-09-27, lissyara
Samba как PDC
Контроллер домена - аналог M$ NT4 домена под самбой, без использования LDAP и прочей хиромантии. Просто и быстро =)
2009-08-30, terminus
ipfw nat
Подробное руководство по ipfw nat, сложные случаи конфигурации.
2009-08-24, levantuev
HotSpot
Установка Hotspot системы в общественное заведение.
2009-08-18, lissyara
diskless
Создание бездисковых терминалов под управлением FreeBSD - с загрузкой по сети. Используются для старта rdesktop и подключения к виндовому серверу терминалов.
2009-07-29, BAV_Lug
Видеонаблюдение
Настройка бюджетного варианта видеонаблюдения на удаленном объекте
2009-07-22, Cancer
OpenLDAP адресная книга
Настройка и создание адресной книги на базе OpenLDAP + phpLDAPadmin
2009-06-30, SergeySL
AimSniff
Руководство по созданию системы мониторинга ICQ-переписки на базе AimSniff, использующей базу данных MySQL для хранения и Web-интерфейс WAS (Web Aim Sniff) для просмотра перехваченных сообщений
2009-06-25, atrium
Управление правами доступа
Полномочия пользователей и файлов, принадлежащих им, формирует концепцию ОС UNIX.
2009-06-16, DNK
Exim+PgSQL
Установка почтовой системы exim+pgsql на FreeBSD 7.1
2009-05-30, mvalery
HDD(mbr) -> HDD(gpt)
Как разбить диск размером более 2TB на разделы, сделать загрузочным, а затем перенести на него информацию с рабочей системы — донора.
2009-05-22, Cancer
SendXMPP
Отправка сообщений на Джаббер сервер по средствам SendXMPP
2009-05-11, Raven2000
Network UPS Tools
Network UPS Tools представляет собой набор программ, которые обеспечивают общий
интерфейс для мониторинга и администрирование UPS оборудования.
2009-04-29, m0ps
IPSEC over GRE with RIP
Пример IPSEC over GRE и динамическим роутингом (RIP), с ADSL в качестве последней мили на оборудовании Cisco.
2009-04-24, WhiteBear777
qemu network
Появилась необходимость поставить на БСД эмулятор(qemu) и настроить в качестве гостевой ОС Windows XP, предоставив ей выход в локалку и в сеть internet...
2009-04-22, vp
freebsd + huawei 162 gsm modem
В статье описывается простой способ подключения модема huawei 162 к freebsd + первичная настройка smstools
2009-04-12, mvalery
Мониторинг RAID
Мониторинг из командной строки RAID компаний AMCC 3ware, HighPoint, Dell (Perc 5/i и PERC 6/i) и LSI (MegaRAID SAS 8408E и SAS1078)
2009-04-09, texnotronic
RAID1 via LAN
Функциональности DRBD во FreeBSD можно добиться примонтировав блочное устройство по сети при помощи GEOM Gate (ggate) и добавив его в зеркало с локальным диском средствами gmirror.
2009-04-03, Raven2000
Оптимизация хоста для CMS
В последнее время на старый и не очень быстрый ПК (Celeron 800 RAM 256) мною было навешано с десяток сайтов и некоторые были из серии тяжелых CMS. И так нам дано FreeBSD 7.1 и ~10 сайтов/CMS.
2009-04-01, atrium
VSFTPD + AD && MySQL
Настройка самого безопасного сервера FTP - vsftpd.
2009-03-31, Dron
Peoplenet + C-motech (3G)
Описание подключения к сети Peoplenet посредством 3G модема С-motech CCu-650U на FreeBSD
2009-03-25, lissyara
mod_auth_external
mod_auth_external - авторизация пользователей в apache c помощью внешней программы - например, системных пользователей.
2009-03-24, gx_ua
Lightsquid
Частично lightsquid может заменить sams: быстрая и простая инсталляция, быстрый парсер, cgi скрипт для динамической генерации отчета, нет привязки к БД, различные графические отчеты, мультиязычный инт
2009-03-18, LHC
Установка Zabbix-1.6
Установка и первоначальная настройка системы мониторинга Zabbix (версия 1.6)
2009-03-16, Cancer
Принт-Сервер Samba+LPD & AD
Простейшая настройка Принт-Сервера на FreeBSD используя Samba+LPD & AD
2009-03-04, Mad_caterpillar
ipsec_vpnc
Настройка VPN IPSec концентратора на FreeBSD 6.2 для клиента cisco с использованием ipsec-tools и авторизацией в активной директории
2009-02-18, Andy
Free-SA
Программа анализирует log файлы Squid'а и формирует по ним отчет.
2009-02-02, Cancer
Openfire Jabber Server
Установка Jabber сервера на примере Openfire
2009-01-28, Cancer
mpd5 + сжатие и шифрование
Установка VPN сервера mpd5 + сжатие и шифрование
2009-01-26, vp
freebsd + webcamera
Подключение и настройка вебмкамеры для работы с freebsd на примере Logitech QCam STX
2009-01-10, Grishun_U_S
конфиг для офисов
В статье разбирается конфиг для офиса, пользователи которого имеют строгие ограничения по портам. Заворачиваем www трафик на транспарентный прокси, а остальное NAT'им. Эффективно делим канал интернет
2008-12-27, Storoge
sftp+chroot
Возникла необходимость дать возможность нескольким пользователям заливать на сервер контент для своих сайтов через sftp, чтобы при этом не страдала безопасность.
2008-12-13, Morty
PurefFTPd
Администрирование pureftpd-сервера с помощью вэб интерфейса Usermanager
|
Комментарии пользователей [23 шт.]