?

Log in

No account? Create an account

Previous Entry | Next Entry

The Hitchhacker's Guide to the debugfs.ext2

Дано: битый раздел, на котором лежит N месяцев работы. Бэкапов нет. e2fsck теряет волю, ситуацию усугубляет растущее кол-во badblock-ов на винте.

livecd storage # e2fsck -n /dev/hdb1
e2fsck 1.38 (30-Jun-2005)
Superblock has an invalid ext3 journal (inode 8).
Clear? no

e2fsck: Illegal inode number while checking ext3 journal for /dev/hdb1
При попытке сказать yes - e2fsck падал по подобию assert(), когда искал root, корневая директория была куском нулей
livecd storage # debugfs -c /dev/hdb1
debugfs 1.38 (30-Jun-2005)
/dev/hdb1: catastrophic mode - not reading inode or group bitmaps
debugfs:  show_super_stats -h
...
Inode count:              7340032
Block count:              14659304
...

# узнаем свободные inode и получаем листинг условно-живых директорий
livecd storage # for ((i=2; $i <= 7340032; i++)); do echo testi '<'$i'>'; done > testi.in
livecd storage # debugfs -f testi.in /dev/hdb1 > testi.out
livecd storage # grep 'Inode [0-9]* is marked in use' testi.out | grep -E -o '[0-9]+' > used.inodes
livecd storage # cat used.inodes | sed 's,.*,ls <&>,' > ls.in
livecd storage # debugfs -f ls.in /dev/hdb1 > ls.out
livecd storage # bzip2 -c ls.out > ls.out.bz2

Крайне полезно этот ls.out залить в sql-базу (например так), чтобы шустро собирать по нему статистику... У меня размер основной таблицы entries (inode, name, curdir, size) индексированной базы (схема прилагается) получился под 100 мегабайт с 60гигового раздела.
Затем можно пополнить базу следующими (НЕ абсолютно верными) наблюдениями:
-- особенно это не верно, пожалуй: INSERT INTO directories SELECT inode, curdir FROM entries GROUP BY inode HAVING COUNT(*) > 1;
INSERT INTO inodes SELECT inode, COUNT(*) FROM entries GROUP BY inode;
INSERT INTO broken_dirs SELECT entries.inode FROM entries LEFT JOIN entries AS dirs ON (dirs.inode = entries.inode AND dirs.name = '.') WHERE entries.name = '..' AND dirs.name IS NULL GROUP BY entries.inode;
INSERT INTO hardlinks SELECT inodes.inode FROM inodes LEFT JOIN entries ON (inodes.inode = entries.inode AND (entries.name IN ('.', '..'))) WHERE nlink > 1 AND entries.name IS NULL;


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

Теперь ищем детей / (inode-2) и возвращаем их на место
mysql> select * from entries where inode = 2;
+-------+---------+------+------+
| inode | curdir  | name | size | # комментарий, изходя из содержания
+-------+---------+------+------+
|     2 | 2392065 | ..   |   12 | /var
|     2 | 6275073 | ..   |   12 | /home
...
+-------+---------+------+------+
17 rows in set (0.00 sec)
mysql> select * from entries where curdir = 2392065;
+---------+---------+---------+------+
| inode   | curdir  | name    | size |
+---------+---------+---------+------+
| 2392065 | 2392065 | .       |   12 |
|       2 | 2392065 | ..      |   12 |
| 2392066 | 2392065 | lock    |   12 |
| 2392067 | 2392065 | run     |   12 |
| 2392068 | 2392065 | backups |   16 |
| 2392069 | 2392065 | cache   |   16 |
... # да, это явно /var
+---------+---------+---------+------+
15 rows in set (0.03 sec)

debugfs:  clri <2>
debugfs:  set_inode_field <2> mode 040755
debugfs:  set_inode_field <2> links_count  17
debugfs:  find_free_block 1
Free blocks found: 33869
debugfs:  set_inode_field <2> bmap[0] 33869
debugfs:  set_inode_field <2> blocks 8
debugfs:  mkdir <2>
debugfs:  ls <2>
 12  (12) .    2  (12) ..    12  (4072) <2>
debugfs:  unlink <2>/<2>
debugfs:  unlink <2>/.
debugfs:  unlink <2>/..
debugfs:  ls
 0  (4096) .
debugfs:  ln <2> <2>/.
debugfs:  ln <2> <2>/..
debugfs:  ls
 2  (12) .    2  (4084) ..
debugfs:  ln <2392065> <2>/var
skipped
debugfs:  ln <6275073> <2>/home
debugfs: ^D
livecd ~ # e2fsck  /dev/hda1

А потом устраиваем большое переименование /lost+found

livecd ~ # ls /mnt/slave/lost+found | { echo "lock tables lostnfound write;" ; sed 's,#,,;s,.*,insert into lostnfound values(&);,'; } | mysql ext2backup
livecd ~ # { echo "select inode, curdir, name from lostnfound inner join entries using (inode) where name != '.' and name != '..';" | mysql ext2backup | while read inode curdir name; do base="/mnt/slave/smth-found"; echo "mkdir -p \"$base/#$curdir\"; mv \"/mnt/slave/lost+found/#${inode}\" \"$base/#$curdir/$name\""; done; } | sed 1d > renamer.sh
livecd ~ # { echo "select lostnfound.inode as lostinode, if(parent.name <=> null, concat('#', entries.inode), parent.name) from lostnfound inner join entries on (entries.name = '..' and curdir = lostnfound.inode) left join entries as parent on (parent.name != '.' and parent.name != '..' and parent.inode = entries.inode);" | mysql ext2backup | while read inode curdir; do base="/mnt/slave/smth-found"; echo "mkdir -p \"$base/$curdir\"; mv \"/mnt/slave/lost+found/#${inode}\" \"$base/$curdir/#$inode\""; done; } | sed 1d > renamer.sh

После чего почти все в почти читаемом виде с ФС почти восстановлено (в lost+found у меня осталось после данной махинации процентов 15% от первоначального объема).

И не могу напоследок не процитировать БОР:
DiriMobile
смотри: начинаем выпуск пива с названием "БУДУЩЕЕ", и в зависимости от пожеланий клиентов впариваем им либо светлое будущее либо темное...

Метки:

Comments

( 18 комментариев — Оставить комментарий )
denis_dda
20 май, 2007 12:07 (UTC)
ты злодей
как такое можно осилить?
нет слов
darkk
20 май, 2007 12:28 (UTC)
Re: ты злодей
Не спорю, слов мало ;)
Но это и не руководство к действию, а просто этакий консольный screencast.
denis_dda
20 май, 2007 13:49 (UTC)
Re: ты злодей
в смысле, у меня нет слов, ты много сделал.
doktorpz
20 май, 2007 13:16 (UTC)
Re: ты злодей
Думаю, когда инфа с винта нужна, а денег на восстановление нету, то такой способ самое то... Да и желание разобраться стимулируется... +)
darkk
20 май, 2007 13:26 (UTC)
Re: ты злодей
Данный случай был интересен еще тем, что восстанавливаемая железка стояла в США.
А там и ценник на восстановление другой, да и искать из Сибири чудо-мастера на другой стороне Земли - удовольстиве странное. %)
doktorpz
20 май, 2007 14:09 (UTC)
Re: ты злодей
Мораль сей басни такова, backup всегда, иначе всем хана...
darkk
20 май, 2007 14:12 (UTC)
Re: ты злодей
несколько постов назад про бэкапы уже сказано %)
doktorpz
20 май, 2007 14:20 (UTC)
Re: ты злодей
Сильно...
normanponenti
6 авг, 2008 05:23 (UTC)
Как тут уже сказали любой опыт это опыт, а уж тем более такой, думаю это позволит вам в дальшейшем сэкономить много времени и нервов.
vicentewhetzel
6 авг, 2008 06:19 (UTC)
У остальных если слово повторяется 5 очков, другое слово - нет слова -0.
exanode
2 июн, 2007 19:01 (UTC)
класс! спасибо за идею с mysql, ибо я в свое время так и не дошел, как debugfs кашерно юзать.
darkk
2 июн, 2007 20:09 (UTC)
Я просто не знаю способа лучше для обработки больших массивов информации в наколенных условиях.
irreconsible
19 окт, 2008 17:58 (UTC)
спасибо, познавательно
(Анонимно)
15 авг, 2009 00:11 (UTC)
Вопрос по теме
Произошел сбой (винт новый в норме, а драйвер ядра к недорогому SATA-контроллеру плохой и по сей день, как оказалось). fsck постоянно находит в одном единственном inode неправильные блоки, 11 очищает, а потом заявляет, что вообще-то их слишком много, идет дальше до конца. А потом начинает проверку заново, снова находит и очищает следующие 11 и т. д. Ну, до Нового Года (вот не знаю этого или какого другого) ждать не хочется. Я вооружился debugfs и выяснил, что inode принадлежит удаленному мною файлу. Т.е. этот весь inode можно было бы спокойно очистить. Но вот незадача. После kill_file <19161090> debugfs уходит в segfault, т.к. она не может обработать ошибочный блок (т.е. номер выходит за пределы фс). Странно, на то ж она и debugfs, чтобы справляться именно с дефектами!? Когда делаю clri <19161090> (stat <19161090> показывает теперь, что все чисто) freei <19161090> (inode is not in use) kill_file <19161090> close, то после open снова все на месте (открывал я на запись). Удивительно! Т.е. ext2fs будет бесконечно всего по 11 блоков очищать, а с debugfs я вообще ничего не могу достигнуть. Может вам придет какая идея? Заранее спасибо!
darkk
15 авг, 2009 05:57 (UTC)
Re: Вопрос по теме
Первая же моя идея проста и незатейлива — взять и исправить ошибку в debugfs, т.к. segfault — это всегда ошибка приложения.

Я думаю, после clri уже бессмысленно делать freei/kill_file, а можно делать сразу close и потом прогнать fsck, чтоб блоки пометить как свободные.
(Анонимно)
15 авг, 2009 11:40 (UTC)
Re: Вопрос по теме
Большое спасибо за ваш ответ!

Только что скомпилировал последнюю версию e2fsprogs. Там ошибка с сегментацией уже исправлена (удивительно, что в версии от октября 2008 она еще была - как же люди раньше-то ей пользовались?).

Итак kill_file отработала успешно, но неправильные блоки она по-прежнему не считает своим долгом удалять.

clri по-прежнему очищает успешно inode, но после close, open все в inode снова видно. Странно. Такое впечатление, что после команды close debugfs обнаруживает, что этот inode еще где-то упомянут и игнорирует в итоге применение команды clri...

fsck не могу прогонять, т.к. неправильных блоков очень много, а за один проход (минут 10) fsck очищает лишь 11 из них.

Андрей
darkk
15 авг, 2009 12:22 (UTC)
Re: Вопрос по теме
Да не за что :-D

Очевидный совет #2 — найти по сообщению, выдаваемому fsck, нужную строчку кода в fsck и зарубить ограничение в 11 блоков.
(Анонимно)
17 авг, 2009 14:47 (UTC)
Re: Вопрос по теме
Место нашел, но пока не хочется таким жестоким способом решать эту проблему. "Поигравшись" с двумя другими пострадавшими файлами, выяснил, что изменения над ними сохраняются после close. "Восстановив" их, пустил проверку fsck. Он удалил как всегда следующие 11 блоков того файла, потом заявил, что их слишком много - лучше очищу весь inode, ОК, пошел дальше. Остановился на двух "восстановленных" файлах, у каждого более 11 инвалидных блоков, тоже предложил очистить весь inode каждого из них. Перезапуск проверки: спотыкается на том "загадочном" файле и в тоже время операция по очищению inode 2 "восстановленных" прошла успешно - о них на pass1 больше ни слова. Т.е. debugfs и fsck корректно их обрабатывают. При этом что-то не так с тем одним файлом, потому что обе некорректно с ним работают. Похоже, какой-то глюк? Написал в субботу в support разработчикам - пока ответа нет. Т.к. речь идет о восстановлении данных, хотелось бы чтобы соответствующие проги не имели явных багов, а то такое будет...

Андрей
( 18 комментариев — Оставить комментарий )

Profile

darkk
Leonid Evdokimov
Website
Разработано LiveJournal.com
Designed by Tiffany Chow