md raid5:将md内部扇区号转换为偏移量


8

TL; DR摘要:将md扇区号转换为/dev/mdX设备内的偏移量,以及如何使用进行调查xfs_db。扇区号来自sh->sectorlinux/drivers/md/raid5.c:handle_parity_checks5()

我不知道MD的内部原理,所以我不知道该如何处理printk我添加的日志记录的输出。

偏移到组件设备中(对于dd十六进制编辑器或查看器)也将很有趣。

我想我应该在Linux突袭邮件列表中问这个问题。它是仅订阅者,还是可以不订阅而发布?


我将xfs直接放在桌面上的4个磁盘的MD RAID5上(没有LVM)。最近的mismatch_cnt清理发现非零值(实际上是8,因为md一次在4kiB页上运行)。

这是RAID5,而不是RAID1 / RAID10 mismatch_cnt在正常操作期间,其中!= 0可能会发生。(此Wiki页面底部的其他链接可能对某些人有用。)

我可以盲目地做repair,但是那时我不知道该检查哪个文件可能的损坏,除了失去选择哪种重建方法的机会。 Frostschutz对类似问题的答案是我发现的唯一回溯到文件系统差异的建议。它既麻烦又缓慢,我宁愿使用更好的方法来首先将其缩小到几个文件。


内核补丁添加日志

奇怪的是,md的检查功能不会报告发现错误的位置我加入了printk在MD / raid5.c记录sh->sectorif该增量分支mddev->resync_mismatcheshandle_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.

现在我不知道该如何处理该扇区号。(aka )sh->sector * 512里面是线性地址吗?它是每个组件设备中的一个扇区号(因此它指的是三个数据和一个奇偶校验扇区)吗?我猜是后者,因为RAID5中的奇偶校验不匹配意味着md设备的N-1个扇区处于危险之中,彼此之间被条带单元偏移。扇区0是组件设备的最开始,还是在超级块之后的扇区或其他内容?我是否应该计算/记录更多信息?/dev/md/t-r5/dev/md125handle_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

我猜不是,因为我从所有四个RAID组件中得到4k的零,并且0^0 == 0,那应该是正确的奇偶校验,对吗?

我看到的另一个在md中使用扇区地址的地方是for sync_minsync_max(在sysfs中)。 linux-raid列表上的Neil Brown回答了有关扇区号为的驱动器发生故障的问题hdrecover,其中Neil使用全盘扇区号作为MD扇区号。那不对吗?md扇区号不是相对于组件设备(在这种情况下是分区),而不是相对于该分区所属的完整设备吗?


线性扇区到XFS文件名:

在意识到md扇区号可能是用于组件而不是RAID设备之前,我尝试以只读方式使用它xfs_db

Dave Chinner关于如何查找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 3TB驱动器的分区上,以及一个非分区的WD25EZRS绿色电源(慢速)驱动器上,我将用另一个Toshiba替换它。(使用mdadm --replace联机进行此操作时,没有冗余上的空隙。我意识到在复制一份副本之前和之后都应该检查RAID运行状况,以发现问题。那是我检测到不匹配的地方。很可能已经存在很长时间了,因为大约一年前发生了一些崩溃,但是我没有旧的日志,因此mdadm似乎默认不会发送与此相关的邮件(Ubuntu 15.10)。

我的其他文件系统在RAID10f2设备上,该设备由三个较大的HD上的较早分区(对于/ var / tmp为RAID0)组成。RAID5仅用于大容量存储,不能用于/home/

我的驱动器一切正常:SMART错误计数为0,所有驱动器上的所有坏块计数器均已通过,并且通过了长短SMART自检。


这个问题几乎没有答案:


如果printk中的数字是相对于阵列的扇区,则需要将其除以条带宽度,并可能添加起始偏移量以将其转换为相对于组件设备的扇区号。iirc,如果您使用的mdadm元数据格式并不总是以偏移量0开头的数据,则它的起始偏移量将列在的输出中mdadm -E /dev/xxx
psusi '16

还请记住,即使您找到数据的位置并可以验证不匹配,并可以检查损坏的文件的完整性(即使数据确实属于文件;它可能是免费的)空格或fs元数据),那么很有可能甚至可能是奇偶校验也是错误的,因此从屏蔽每个数据驱动器中依次得到的所有可能答案都不正确。
psusi '16

@psusi:谢谢,是的,我知道它可能不是文件的一部分。如果不使我的句子显得笨拙,很难表达这一点。有趣的是,也许所有的重构都不正确,是的,这是可能的。无论哪种方式,我会远远快乐知道要重命名的文件.damaged或东西,而不是只知道有可能是一个坏文件的某处。
彼得·科德斯

Answers:


2

TL; DR sh-> sector是数据部分开始后物理磁盘中的扇区数


设定

这是一个简单的测试设置,以说明:

  • / dev / raidme / rd [0-3],2GB设备
  • / dev / md127在这5个文件上以raid5的形式创建,初始化为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*10240ie上写道0xa00000

您的补丁提供了信息16384,需要注意的一件事是数据不是从0开始的:

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

所以printf "%x\n" $(((4096+16384)*512))说也0xa00000一样。好。


封锁md

现在,要到达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*349152(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(请确保再次停止/启动数组),则返回零。看起来不错。

但是,还有一个问题,如果您的条带大小与我的条带大小一样大(512k),那么我们就没有一个块可以处理,但是有1.5MB的可能数据损坏了……通常情况下,单个文件,但是您需要在xfs_db中进行检查。记住inode早于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.5MB是384个块。我们损坏的段是块6144到6528-恰在此文件的第一段之内。

要查看的其他内容是手工提取块,并检查校验和不完全匹配的地方,希望可以给您3个较小的块。


最后,关于您的补丁程序,我自己不是MD开发人员,但作为前MDadm raid5用户,我会非常感兴趣。我想说一点点努力绝对值得。您提到的清理工作可能很有用,我敢肯定,一旦您提交了补丁程序,开发人员将发表一些评论,但是heck md对于这些错误需要更详细!


恩,很高兴您指出了底层块设备上的位置。就我而言,printf '%#x\n' $(( (259072+4294708224 )*512 ))is 0x20000000000,这显然不是巧合。(确切地说是2TiB。我怀疑是grub-install或某些MBR东西带来的恶作剧)。如果我只是在MD设备中查找偏移量以查找受影响的文件,我不会注意到这一点。(顺便说一句,%#x格式0x为您添加了前缀。)
Peter Cordes

xfs_db只是说了must run blockget first,即使我按照您的示例做了(就像我在问题中张贴的一样)。即使我习惯blockget -v -n -b 12884124672给它一个特定的块。我曾经ddhexdump地发现,居然有在该块不匹配,虽然。三个全为零,第四个在512k条带中的1kiB处设置了一个单一的一位。(非常方便,我不必寻找一种方法对XOR块进行实际的检查以检查冗余。)
Peter Cordes

如果我daddr先使用(在blockget之前),则不会收到错误消息,blockget -v -n而and 根本没有输出blockuse -v -n。万一重要,我的xfsprogs是3.2.1ubuntu1,并且我使用的是Linux 4.2.0-36-generic(不是我的补丁-rc内核)。我的FS正在使用crc=1 isize=512naming =version 2 bsize=4096 ascii-ci=0 ftype=1
Peter Cordes

无论如何,此答案可以正确识别组件设备和md设备上不匹配块的位置。唯一不起作用的是XFS块->文件名部分,这实际上是一个单独的问题。从理论上讲,我可以find -exec xfs_bmap -vpl {} +用来查找包含已知块的文件。
彼得·科德斯

1
不幸的是,我不知道有什么方法可以使xfs_db忽略日志日志(例如,即使不是100%一致,也可以强制执行blockget),或者使内核“刷新”该日志作为umount / mount可以使xfs_db满意。 ..是的,除非您想拖拉东西,否则可能需要稍等片刻才能重新安装。让我保持更新,不要忘了尝试上游补丁:)
Asmadeus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.