md raid5: перевод номеров внутренних секторов md в смещения

8

TL; DR сводка : преобразование номера сектора md в смещения (я) внутри /dev/mdXустройства и как его исследовать xfs_db. Номер сектора от sh->sectorв linux/drivers/md/raid5.c:handle_parity_checks5().

Я не знаю внутренностей MD, поэтому я не знаю точно, что делать с выводом из printkжурнала, который я добавил.

Смещения в компонентные устройства (для ddили шестнадцатеричный редактор / просмотрщик) также были бы интересны.

Полагаю, мне следует спросить об этом в списке рассылки Linux-raid. Это только для подписчиков, или я могу публиковать без подписки?


У меня xfs прямо поверх MD RAID5 из 4 дисков на моем рабочем столе (без LVM). Недавняя очистка обнаружила ненулевое значение mismatch_cnt(на самом деле 8, потому что md работает со страницами размером 4 Кбайт).

Это RAID5, а не RAID1 / RAID10, где mismatch_cnt! = 0 может произойти во время нормальной работы . (Другие ссылки внизу этой вики-страницы могут быть полезны для некоторых людей.)

Я мог бы просто слепо repair, но тогда я бы не знал, какой файл проверять на предмет возможного повреждения, кроме того, что я не мог выбрать, какой путь восстановить. Ответ Фростшуца на похожий вопрос - единственное предложение, которое я нашел для отслеживания различий в файловой системе. Это громоздко и медленно, и я бы предпочел использовать что-то лучше, чтобы сначала сузить его до нескольких файлов.


Ядро патч для добавления регистрации

Как ни странно, функция проверки md не сообщает, где была обнаружена ошибка . Я добавил printkв мкр / raid5.c к необходимо войти sh->sectorв в ifотрасли , который увеличивается mddev->resync_mismatchesвhandle_parity_checks5() (крохотном пятачке , опубликованную на GitHub , первоначально на основе 4,5-rc4 от kernel.org.) Для этого , чтобы быть хорошо для общего использования, было бы , вероятно , потребуется избегайте переполнения журналов при ремонте с большим количеством несоответствий (возможно, только журнал, если новое значение resync_mismatches<1000?). Также возможно только войти для checkи нет repair.

Я почти уверен, что записываю что-то полезное (хотя я и не знаю, что такое MD!), Потому что эта же функция печатает этот номер сектора в случае обработки ошибок вswitch .

Я скомпилировал моё модифицированное ядро ​​и загрузил его, затем снова запустил проверку:

[  399.957203] md: data-check of RAID array md125
...
[  399.957215] md: using 128k window, over a total of 2441757696k.
...
[21369.258985] md/raid:md125: check found mismatch at sector 4294708224    <-- custom log message
[25667.351869] md: md125: data-check done.

Теперь я не знаю точно, что делать с этим номером сектора. Является ли sh->sector * 512линейный адрес внутри /dev/md/t-r5(он же /dev/md125)? Это номер сектора в каждом компонентном устройстве (поэтому он относится к трем данным и одному сектору четности)? Я предполагаю последнее, так как несоответствие четности в RAID5 означает, что N-1 секторы устройства md находятся в опасности, смещены относительно друг друга полосовым модулем. Является ли сектор 0 самым началом компонентного устройства, или это сектор после суперблока или что-то еще? Была ли там дополнительная информация, handle_parity_checks5()которую я должен был рассчитать / зарегистрировать?

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

dd if=/dev/sda6 of=mmblock.0 bs=512 count=8 skip=4294708224
dd if=/dev/sdb6 of=mmblock.1 bs=512 count=8 skip=4294708224
dd if=/dev/sda6 of=mmblock.2 bs=512 count=8 skip=4294708224
dd if=/dev/sdd  of=mmblock.3 bs=512 count=8 skip=4294708224  ## not a typo: my 4th component is a smaller full-disk

# i.e.
sec_block() { for dev in {a,b,c}6 d; do dd if=/dev/sd"$dev" of="sec$1.$dev"  skip="$1"  bs=512 count=8;done; }; sec_block 123456

Я не думаю, потому что я получаю 4k нулей от всех четырех компонентов рейда, и 0^0 == 0, так, должно быть правильное соотношение, верно?

Еще одно место, где я упоминал об использовании адресов секторов в md, - это for sync_minи sync_max(в sysfs). Нейл Браун в списке linux-raid , отвечая на вопрос о неисправном диске с номерами секторов hdrecover, откуда Нил использовал номер сектора полного диска в качестве номера сектора MD. Это не правильно, не так ли? Разве номера секторов md не будут относиться к компонентным устройствам (в данном случае к разделам), а не к полному устройству, частью которого является раздел?


линейный сектор к имени файла XFS:

Прежде чем понять, что номер сектора md, вероятно, относится к компонентам, а не к устройству RAID, я попытался использовать его только для чтения xfs_db:

Очень краткое предложение Дэйва Чиннера о том, как выяснить, как XFS использует данный блок, похоже, не сработало для меня. (Я бы ожидал какой-то результат для некоторого сектора, поскольку число не должно быть за пределами конца устройства, даже если это не несоответствующий сектор)

# xfs_db -r /dev/md/t-r5 
xfs_db> convert daddr 4294708224 fsblock
0x29ad5e00 (699227648)
xfs_db> blockget -nv -b 699227648
xfs_db> blockuse -n       # with or without -c 8
must run blockget first

да? Что я здесь не так делаю? Я думаю, это должен быть отдельный вопрос. Я заменю это ссылкой, если / когда я спрошу это или найду ответ на эту часть где-нибудь еще.

Мой RAID5 практически бездействует, без операций записи и минимального чтения (и noatime, следовательно, чтение не производит записи).


Дополнительные сведения о моей настройке, ничего важного здесь

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


мой /proc/mdstatдля моего массива данных массива:

md125 : active raid5 sdd[3] sda6[0] sdb6[1] sdc6[4]
      7325273088 blocks super 1.2 level 5, 512k chunk, algorithm 2 [4/4] [UUUU]
      bitmap: 0/19 pages [0KB], 65536KB chunk

Он находится на разделах на трех накопителях Toshiba 3 ТБ и однораздельном (медленном) жестком диске WD25EZRS, который я заменяю другим Toshiba. (Используется mdadm --replaceдля того, чтобы сделать это в режиме онлайн без пробелов в избыточности. После одной копии я понял, что должен проверять работоспособность RAID до и после, чтобы обнаруживать проблемы. Именно тогда я обнаружил несоответствие. Возможно, это было в течение долгого времени , поскольку у меня были некоторые сбои почти год назад, но у меня нет старых журналов, и mdadm, похоже, не отправляет почту об этом по умолчанию (Ubuntu 15.10).

Мои другие файловые системы находятся на устройствах RAID10f2, созданных из более ранних разделов на трех больших жестких дисках (и RAID0 для / var / tmp). RAID5 только для массового хранения, а не /homeили /.

С моими дисками все в порядке: количество ошибок SMART равно 0 для всех счетчиков сбойных блоков на всех дисках, а короткие и длинные SMART-тесты пройдены.


почти дубликаты этого вопроса, на которые нет ответов:

Питер Кордес
источник
Если число в вашем printk является сектором относительно массива, то вам нужно разделить его на ширину полосы и, возможно, добавить начальное смещение, чтобы преобразовать его в номер сектора относительно устройства-компонента. iirc, если вы используете формат метаданных mdadm, который не всегда начинает данные с нулевого смещения, то смещение, с которого они начинаются, указывается в выходных данных mdadm -E /dev/xxx.
psusi
Также имейте в виду, что даже если вы обнаружите местоположение данных и сможете проверить несоответствие, и сможете проверить целостность поврежденного файла (если данные даже принадлежат файлу; он может быть просто бесплатным). пробел или метаданные fs), тогда вполне возможно и даже вероятно, что четность также неверна, и поэтому ни один из возможных ответов, которые вы получите от маскировки каждого диска данных по очереди, не будет правильным.
psusi
@psusi: спасибо, да, я знаю, что это не может быть частью файла. Было трудно выразить это, не делая мои предложения действительно неуклюжими. Интересно, что, возможно, ни одна из реконструкций не верна, да, это возможно. В любом случае, я был бы намного счастлив узнать, какой файл переименовать .damagedили что-то в этом роде, вместо того, чтобы просто знать, что где-то есть поврежденный файл.
Питер Кордес

Ответы:

2

TL; DR sh-> сектор - число секторов в физических дисках после начала раздела данных


Настроить

Вот простая настройка теста для иллюстрации:

  • / dev / raidme / rd [0-3], устройства 2 ГБ
  • / dev / md127, созданный как raid5 для этих 5, init'd как xfs и заполненный случайными данными

Теперь, чтобы начать, получить ненулевой блок и перезаписать его

# dd if=/dev/raidme/rd0 bs=1k count=1 skip=10240 | hexdump -C | head
...
# dd if=/dev/zero of=/dev/raidme/rd0 bs=1k count=1 seek=10240
...
# dd if=/dev/raidme/rd2 bs=1k count=1 skip=10240 | hexdump  -C | head
1024 bytes (1.0 kB, 1.0 KiB) copied, 8.6021e-05 s, 11.9 MB/s
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400

Убедитесь, что кэш dm / md очищен путем остановки / повторной сборки массива, и проверьте:

# mdadm --stop /dev/md127
# mdadm --assemble /dev/md127 /dev/raidme/rd*
# echo check > /sys/class/block/md127/md/sync_action
# dmesg | tail
...
[ 1188.057900] md/raid:md127: check found mismatch at sector 16384

Блок на дисках

Итак, сначала давайте проверим 16384 совпадения с тем, что мы написали. Мой рейд имеет 512K полосы , так что я уверен , что я написал что - то выровненное быть легко совпадет, мы писали в 1024*10240то есть 0xa00000.

Ваш патч дает информацию 16384, о которой нужно знать, что данные не начинаются с 0:

# mdadm -E /dev/raidme/rd0 | grep "Data Offset"
    Data Offset : 4096 sectors

Так printf "%x\n" $(((4096+16384)*512))говорит, что это тоже 0xa00000хорошо. Хорошо.


Блок в мд

Теперь узнать, где это находится на конце md, на самом деле проще: это просто позиция, указанная во времени секторов, number_of_stripesнапример, для меня у меня 4 диска (3 + 1) и 3 полосы.

Здесь это означает, 16384*3*512например 0x1800000. Я заполнил диск довольно хорошо, так что легко проверить, просто читая диск и ища 1k нулей:

# dd if=/dev/md127 bs=1M | hexdump -C | grep -C 3 '00 00 00 00 00 00'
... some false positives...
01800000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
01800400  6b a8 9e e0 ad 88 a8 de  dd 2e 68 00 d8 7a a3 52  |k.........h..z.R|

Блок в xfs

Круто. Давайте посмотрим, где это сейчас находится в xfs. 16384*3is 49152(daddr принимает номер сектора):

# xfs_db -r /dev/md127
xfs_db> blockget -n
xfs_db> daddr 49152
xfs_db> blockuse -n
block 6144 (0/6144) type data inode 2052 d.1/f.1

Конечно же, нули в этом файле:

# dd if=/mnt/d.1/f.1 bs=1M | hexdump -C | grep -C 3 '00 00 00 00 00'
...
03680000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
03680400  6b a8 9e e0 ad 88 a8 de  dd 2e 68 00 d8 7a a3 52  |k.........h..z.R|

Если мы перезаписываем этот файл, то нули исчезают в / dev / raidme / rd0 с правильным смещением (просто добавьте его в другой файл). Если вы снова напишите в / dev / raidme / rd0 (убедитесь, что вы снова остановили / запустили массив), то нули вернутся. Выглядит хорошо.

Однако есть еще одна проблема: если размер вашей полосы здесь такой же, как у меня (512 КБ), то у нас нет ни одного блока для обработки, но возможно повреждение 1,5 МБ данных ... Достаточно часто это может произойти один файл, но вы должны это проверить, вернувшись в xfs_db. Помните, инод раньше был 2052.

xfs_db> inode 2052
xfs_db> bmap
data offset 0 startblock 256 (0/256) count 17536 flag 0
data offset 17536 startblock 122880 (0/122880) count 4992 flag 0
data offset 22528 startblock 91136 (0/91136) count 3072 flag 0

Размер блока здесь составляет 4096 байт (см. xfs_info), Поэтому наши 1,5 МБ составляют 384 блока. Наш поврежденный сегмент - это блок с 6144 по 6528 - в первом сегменте этого файла.

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


Наконец, о вашем патче я сам не md dev, но как бывший пользователь raid5 mdadm я был бы весьма заинтересован. Я бы сказал, что это определенно стоит того, чтобы немного его подтолкнуть. Упомянутая вами очистка может быть полезной, и я уверен, что разработчики получат некоторые комментарии после того, как вы отправите патч, но, черт возьми, md должен быть более подробным об этих ошибках!

Asmadeus
источник
Да, я рад, что вы указали позицию на нижележащих блочных устройствах. В моем случае printf '%#x\n' $(( (259072+4294708224 )*512 ))есть 0x20000000000, что, очевидно, не случайно. (Это точно 2TB. Я подозреваю, что некоторые махинации из grub-install или что-то вроде MBR). Я бы не заметил этого, если бы просто искал смещения на устройстве MD, чтобы найти поврежденный файл. (Кстати, %#xформат добавляет 0xпрефикс для вас.)
Питер Кордес
xfs_dbпросто говорит must run blockget first, хотя я только что сделал (точно так же, как я написал в вопросе), после следования вашему примеру. Даже если я использую, blockget -v -n -b 12884124672чтобы дать ему определенный блок. Я использовал ddи hexdumpобнаружил, что на самом деле в этом блоке есть несоответствие. Все три равны нулю, а четвертый имеет один однобитный бит 1 кБ в полосу 512 Кбайт. (Очень удобно, что мне не пришлось искать способ на самом деле блокировать XOR, чтобы проверить избыточность.)
Питер Кордес
Если я использую daddrсначала (перед blockget), я не получаю сообщение об ошибке, просто не выводить вообще из blockget -v -nи blockuse -v -n. В случае, если это имеет значение, мой xfsprogs - 3.2.1ubuntu1, и я использую Linux 4.2.0-36-generic (не мое исправленное ядро ​​-rc). Моя ФС использует crc=1 isize=512, naming =version 2 bsize=4096 ascii-ci=0 ftype=1
Питер Кордес
В любом случае, этот ответ правильно идентифицирует местоположение блока несовпадения на компонентных устройствах и на устройстве md. Единственный кусок, который не работает, это блок XFS block-> filename, который на самом деле является отдельным вопросом. Я мог бы теоретически использовать find -exec xfs_bmap -vpl {} +поиск файла, содержащего известный блок.
Питер Кордес
1
К сожалению, я не знаю ни одного способа заставить xfs_db игнорировать журнал журнала (например, принудительно блокировать блокировку, даже если он не соответствует 100%), или заставить ядро ​​«сбрасывать» этот журнал как umount / mount, что сделает xfs_db счастливым. .. Так что, да, если вы не хотите что-то запутать, может потребоваться немного подождать, пока вы не сможете перемонтировать. Держите меня в курсе и не забудьте попробовать вышедший патч :)
Asmadeus