Поломался однажды RAID10 массив. Как обычно, все произошло внезапно: однажды перезапустили сервер, и получили «(что-то там) … not found». С поврежденным (degraded) массивом сервер стартовать отказался. Массив работал на полусофтовом-полухардварном псевдоконтроллере материнской платы Intel. Физически все жесткие диски оказались здоровыми, хотя для нижеописанного это не критично.
Далее следует описание восстановления информации с массива из серии «с помощью швейцарского перочинного ножа», т.е. без применения изощрённых средств восстановления. Если конкретно, понадобится компьютер с любым *nix и интерпретатором python3. Можно, конечно, воспользоваться программами вроде R-Studio, однако, по-моему это слишком простая задача для них.
Итак, делаем следующее. Открываем в бинарном редакторе все 3 диска и выбираем из них пару striped дисков, т.е. на которых чередующимися блоками составляют весь массив (как RAID 0). Делаем образы обоих жестких дисков в файлы с помощью замечательной утилиты dd
по типу
dd if=/dev/sdX of=/tmp/vY.hdd bs=32M
В итоге получаем два больших файла v0.hdd, v1.hdd. С самими HDD далее не работаем.
Снова открываем с помощью бинарного редактора какой-нибудь из образов и определяем размер stripe-элемента (chunk size). Сделать это не сложно даже «невооружённым взглядом»: ищется несколько этих кусков с чёткими границами. Легче всего это сделать на файле с вразумительным содержимом, или даже на любом — если свободное место (почти) заполнено нулями. В нашем случае размер stripe оказался 64K. При этом на одном из образов в начальном секторе сразу обнаружился MBR, а во втором нечто совсем не похожее на MBR. Так стал понятен порядок stripe от разных дисков.
Осталось почти ничего: брать поочередно chunks куски с разных дисков, складывать их последовательно и получить образ всего массива. Пишем для этого элементарный скрипт на питоне:
#!/usr/bin/python3 """RAID0 recovery utility.""" dev0 = '/tmp/v1.hdd' dev1 = '/tmp/v0.hdd' DEV_OUT = '/tmp/out.hdd' # stripe 64k STRIPE = 64 * 1024 MAX_COUNT = 500 * 2**29 // STRIPE MAX COUNT if __name__ == '__main__': f0 = open(dev0, 'rb') f1 = open(dev1, 'rb') f_out = open(DEV_OUT, 'wb') offset = 0 while offset < MAX_COUNT: d0 = f0.read(STRIPE) d1 = f1.read(STRIPE) if d0 and d1: f_out.write(d0) f_out.write(d1) offset += 1 else: print("One of input files are finished. Read: {0} blocks.".format(offset)) break f0.close() f1.close() f_out.close()
Запускаем скрипт, оставляем его на ~10 минут и на выходе получаем полный образ диска. Разделы из него успешно монтируются самостоятельно или могут быть (всем образом) записаны на физический HDD. Так, совсем несложно и без дорогого софта, можно восстановить запоротый RAID10-массив.