Bsdadmin.ru

Записки администратора FreeBSD

Путь на сайте

Домашняя FreeBSD Восстановление данных и лечение диска с помощью dd

Восстановление данных и лечение диска с помощью dd

Для начала нужно немедленно отмонтировать все разделы диска во избежание потери данных.
Посмотрим SMART подозрительного диска на предмет подтверждения  подозрений. А лучше
сразу запустить самодиагностику HDD, выполнив команду smartctl -t long /dev/ad6, а потом уже
смотреть информацию смарта. Для этого воспользуемся утилитой smartctl.
Она выдаёт много интересного:
gva# smartctl -A /dev/ad6
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE       UPDATED   WHEN_FAILED RAW_VALUE
  5 Reallocated_Sector_Ct   0x0033   100   100   036    Pre-fail   Always        -       0
197 Current_Pending_Sector  0x0012   100   096   000    Old_age    Always        -       169
198 Offline_Uncorrectable   0x0010   100   096   000    Old_age    Offline       -       169
 
На диске пока не появилось бэд-блоков, однако появились подозрительные блоки в количестве
169 штук, которые были выявлены в ходе самодиагностики винта. Это блоки диска, при чтении которых
произошёл  сбой.
 Вот отрывок из /var/log/messages: 
Jan 14 22:03:17 gva kernel: (ada1:ahcich1:0:0:0): READ_DMA48. ACB: 25 00 2f d1 c1 40 9f 00 00 00 20 00
Jan 14 22:03:17 gva kernel: (ada1:ahcich1:0:0:0): CAM status: ATA Status Error
Jan 14 22:03:17 gva kernel: (ada1:ahcich1:0:0:0): ATA status: 51 (DRDY SERV ERR), error: 40 (UNC )
Jan 14 22:03:17 gva kernel: (ada1:ahcich1:0:0:0): RES: 51 40 38 d1 c1 00 9f 00 00 00 00
Jan 14 22:03:17 gva kernel: (ada1:ahcich1:0:0:0): Retrying command
Jan 14 22:03:21 gva kernel: (ada1:ahcich1:0:0:0): READ_DMA48. ACB: 25 00 2f d1 c1 40 9f 00 00 00 20 00
Jan 14 22:03:21 gva kernel: (ada1:ahcich1:0:0:0): CAM status: ATA Status Error
Jan 14 22:03:21 gva kernel: (ada1:ahcich1:0:0:0): ATA status: 51 (DRDY SERV ERR), error: 40 (UNC )
Jan 14 22:03:21 gva kernel: (ada1:ahcich1:0:0:0): RES: 51 40 38 d1 c1 00 9f 00 00 00 00
Jan 14 22:03:21 gva kernel: (ada1:ahcich1:0:0:0): Retrying command
Jan 14 22:03:25 gva kernel: (ada1:ahcich1:0:0:0): READ_DMA48. ACB: 25 00 2f d1 c1 40 9f 00 00 00 20 00
 
Поищем ещё не выявленные ошибки. Следует проверить диск полностью на предмет ещё не выявленный сбойных
секторов. Диск это может сделать собственными силами, но есть ещё один — утилитой dd. 
 
gva# dd if=/dev/ad6 of=/dev/null bs=65536 conv=noerror
dd: /dev/ad6: Input/output error
20939144+0 records in
20939144+0 records out
1372267741184 bytes transferred in 13768.709737 secs (99665674 bytes/sec)
dd: /dev/ad6: Input/output error
dd: /dev/ad6: Input/output error
20939630+0 records in
20939630+0 records out
1372301295616 bytes transferred in 14014.402646 secs (97920784 bytes/sec)
dd: /dev/ad6: Input/output error
22892776+1 records in
22892776+1 records out
1500300992512 bytes transferred in 15608.577596 secs (96120289 bytes/sec)
 
Как видно из листинга, с помощью утилиты dd мы спровоцировали не читаемые блоки заявить о себе.
Параметр conv=noerror говорит, что следует продолжать работу не смотря на встреченную ошибку.
Хотя размер блоков на диске 512 байт, для ускорения работы программы был задан размер блока 65536 байт
(bs=65536). Таким образом мы выявим не сам сбойный 512-байтовый блок, а группу блоков, среди которых и
находится сбойный. При необходимости можно уточнить поиск с меньшим размером блоков.
Но пока такой необходимости нет. Зато есть необходимость выявить номер 512-байтового блока,
а точнее его LBA-адрес — именно он понадобится в дальнейшем. Будем вычислять его по формуле:
 
бн = Бн * Бр / бр - 1
бн = 20939144 * 65536 / 512 - 1 = 2680210431
 
где:
бн — номер искомого 512-байтового блока диска (2680210431),
Бн — номер 65536-байтового блока, который выдала dd (20939144),
Бр — размер блока, который выдала dd (65536),
бр — размер блока, номер которого мы ищем (512).
- 1 — смещение количества блоков, относительно нумерации LBA.
 
Таким образом мы вычисляем номера физических блоков для всех сбойных блоков, номера которых нам указал dd.
Я не знаю номера это именно не прочитанных блоков или последних прочитанных, поэтому, на всякий случай, к
вычисленным номерам добавлю ещё набор этих же номеров, увеличенных на единицу. Кроме того самый последний
номер блока в выдаче dd указывает не на сбойный блок, а на последний, поэтому его мы в расчёт не берём.
Теперь, когда номера сбойных блоков мы знаем, нужно смонтировать файловые системы, к которым относятся не
читаемые блоки. Узнать, что это за файловые системы можно программой bsdlabel:
gva# bsdlabel /dev/ad6s1
# /dev/ad6s1:
8 partitions:
#          size     offset    fstype   [fsize bsize bps/cpg]
  a: 2930277089         16    unused        0     0
  c: 2930277105          0    unused        0     0     # "raw" part, don't edit
 
Чтобы понять, в каком разделе находится блок, нужно в колонке offset найти строку с меньшим наиболее близким
к номеру блока числом. К примеру, если блок имеет номер 2680210431, значит наиболее близкое к нему число в
колонке offset — 16, что означает, что блок находится в разделе a. И это не удивительно, поскольку в примере 
всего один раздел.Полный путь к разделу — /dev/ad6s1a, его мы и монтируем. Сделаем это в режиме чтения во
избежание всяческих неожиданностей:
  gva# mount -o ro -t ufs /dev/ad6s1a /mnt
 
Теперь, когда файловая система смонтирована, а номера сбойных блоков мы знаем, нужно посмотреть что за файлы
в них находятся. Для этого воспользуемся утилитой fsdb.
 gva# fsdb -r /dev/ad6s1a
** /dev/ad6s1a (NO WRITE)
Examining file system `/dev/ad6s1a'
Last Mounted on /usr/home/disk
current inode: directory
I=2 MODE=40755 SIZE=512
        BTIME=Jan 8 00:52:13 2011 [0 nsec]
        MTIME=Jul 16 23:39:29 2013 [0 nsec]
        CTIME=Jul 16 23:39:29 2013 [0 nsec]
        ATIME=Jan 12 03:13:30 2014 [0 nsec]
OWNER=gva GRP=gva LINKCNT=10 FLAGS=0 BLKCNT=4 GEN=3e80ec28
fsdb (inum: 2)> findblk 2680210432
2680210432: data block of inode 165523470
fsdb (inum: 2)> findblk 2680210560
2680210560: data block of inode 165523470
fsdb (inum: 2)> findblk 2680272640
2680211968: data block of inode 165523470
fsdb (inum: 2)> findblk 2680272768
2680212096: data block of inode 165523470
fsdb (inum: 2)> q
 
Программа fsdb выдала нам иноды, тех файлов, что находятся в вычисленных нами блоках диска. Как видно это один
и тот же инод, что означает, что все не читаемые области приходятся на один файл, что облегчает нашу работу.
 Теперь, когда известен инод повреждённого файла, можно найти путь к файлу с помощью программы find:
gva# find /mnt -inum 165523470
/mnt/private/video.file
 Файл найден и теперь приступим к его восстановлению. Для этого снова  воспользуемся утилитой dd.
  gva# dd if=/mnt/private/video.file of=/usr/home/gva/video.file bs=512 conv=noerror,sync
dd: /mnt/private/video.file: Input/output error
4938784+0 records in
4938784+0 records out
2528657408 bytes transferred in 255.684458 secs (9889758 bytes/sec)
dd: /mnt/private/video.file: Input/output error
dd: /mnt/private/video.file: Input/output error
4938785+0 records in
4938785+0 records out
2528657920 bytes transferred in 316.122989 secs (7998969 bytes/sec)
dd: /mnt/private/video.file: Input/output error
70658472+0 records in
70658472+0 records out
36177137664 bytes transferred in 15758.371732 secs (2295741 bytes/sec)
 
Как  понятно из листинга, мы скопировали повреждённый файл в другое место, игнорируя ошибки чтения (noerror) 
и заполняя непрочитанные места нулями (sync). Так же был выбран самый маленький размер блока в 512 байт 
(bs=512) для более точного выявления сбойных секторов и более полной копии.
Если вдруг при копировании не возникло ошибок, значит был неправильно рассчитан сбойный физический блок. Требуется более подробный поиск. Его снова осуществим утилитой dd, но теперь укажем ей конкретные блоки для чтения. Для этого воспользуемся такой формулой:
 бк = Бр / бр 
бк = 65536 / 512 = 128
 
где
бк — количество 512-байтовых блоков, в которых следует уточнить поиск (128),
Бр — размер блока, который выдала dd при грубом поиске (65536),
бр — размер блока, количество которых мы ищем (512).
Теперь можно уточнить поиск вот такой командой:
gva# dd if=/dev/ad6 of=/dev/null bs=65536 conv=noerror count=128
 
Опция count подскажет dd сколько блоков прочитать. В результате мы получим уже точные номера физических блоков, в которых определим иноды, по которым определим имена файлов, которые скопируем в безопасное место.
Итак, был скопирован повреждённый файл, но на диске полно файлов не повреждённых, их тоже надо бы скопировать в более надёжное место. 
Нужно затереть сбойные блоки, чтобы спровоцировать контроллер винчестера их перераспределить, либо, чтобы он
убедился, что они в порядке. Прежде, чем заняться лечением диска, его нужно перемонтировать в режиме записи,
но FreeBSD не даст этого сделать, так-как на диске выявлены проблемы, и потребует его проверить.
  gva# umount /mnt
gva# fsck -y -f -t ufs /dev/ad6s1a
gva# mount -t ufs /dev/ad6s1a /mnt
Так-как затирать не читаемые блоки по номерам лениво, а файл с ними всего один, будем затирать повреждённый файл. dd сама разберётся что к чему:
g va# dd if=/dev/zero of=/mnt/private/video.file bs=512
/mnt: write failed, filesystem is full
dd: /mnt/private/video.file: No space left on device
644384545+0 records in
644384544+0 records out
329924886528 bytes transferred in 5154.050639 secs (64012737 bytes/sec)
Судя по листингам, восстанавливаемый файл при копировании имел размер 36177137664 байт, а после заполнения нулями распух в десять раз — до 329924886528 байт… Это вовсе не потому, что я забыл указать опцию count. Дело в том, что при записи в файл совсем не обязательно данные должны писаться в те же блоки, где была предыдущая версия файла.
Так что, плохие блоки могли бы и не быть затёртыми. Поэтому нужно перезаписать нулями и свободное место в 
профилактических целях.  Если свободного места много, следует всё же заморочиться с затиранием конкретных блоков по номерам, быстрее будет.  Устройство /dev/zero — файл бесконечного размера и его копирование в другой файл приведёт к тому, что целевой файл будет расти бесконечно, пока не исчерпается свободное место на диске. Это и произошло.
Итак, повреждённый файл был перезаписан нулями. Проверим на сколько это помогло, прочитав этот файл:
gva# dd if=/mnt/private/video.file of=/dev/null bs=65536 conv=noerror
5034254+1 records in
5034254+1 records out
329924886528 bytes transferred in 3758.004039 secs (87792584 bytes/sec)
Как видим, ошибок больше не возникает. Это означает, что лечение помогло. Заглянем в SMART.
gva# smartctl -A /dev/ad6
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE       UPDATED   WHEN_FAILED RAW_VALUE
  5 Reallocated_Sector_Ct   0x0033   100   100   036    Pre-fail   Always        -       0
197 Current_Pending_Sector  0x0012   100   096   000    Old_age    Always        -       0
198 Offline_Uncorrectable   0x0010   100   096   000    Old_age    Offline       -       0
 
SMART больше не подозревает ни одного блока в нечитаемости, а так же ни одного блока не было перераспределено. А это значит, что диск не имеет физических повреждений и может использоваться далее. Ошибки на нём возможно были вызваны плохим кабелем данных, либо неплотным контактом, а может быть это был сбой по питанию, а может и другая причина из миллиона других возможных причин.
Но прежде, чем расслабиться и вновь начать нещадно эксплуатировать несчастную железку, необходимо снова повторить проверку всего винта на предмет не читаемых областей с помощью dd и полную само-диагностику внутренними средствами жёсткого диска.

Домашняя FreeBSD Восстановление данных и лечение диска с помощью dd