TL;DR 总结:将 md 扇区号转换为设备内的偏移量/dev/mdX
,以及如何使用 进行调查xfs_db
。扇区号从sh->sector
inlinux/drivers/md/raid5.c:handle_parity_checks5()
。
我不了解 MD 内部结构,所以我不知道如何处理printk
我添加的日志记录的输出。
组件设备(对于dd
十六进制编辑器/查看器)的偏移也很有趣。
我想我应该在 Linux-raid 邮件列表上询问这个问题。是否仅限订阅者,或者我可以在不订阅的情况下发帖吗?
我的 xfs 直接位于桌面上 4 个磁盘的 MD RAID5 之上(无 LVM)。最近的一次清理检测到一个非零mismatch_cnt
(实际上是 8,因为 md 一次在 4kiB 页面上运行)。
这是 RAID5,不是 RAID1/RAID10其中mismatch_cnt
!= 0 可能在正常操作期间发生。 (其他链接在底部这个维基页面可能对某些人有用。)
我可以盲目地这样做repair
,但是除了失去选择重建方式的任何机会之外,我不知道要检查哪个文件是否可能损坏。 Frostschutz 在类似问题上的回答这是我找到的用于追踪文件系统差异的唯一建议。它既麻烦又缓慢,我宁愿使用更好的东西来首先将其范围缩小到几个文件。
内核补丁添加日志记录
奇怪的是,md 的检查功能不会报告发现错误的位置。 我printk
在md/raid5.c中添加了一个用于登录sh->sector
增量的if
分支mddev->resync_mismatches
handle_parity_checks5()
(小补丁发布在 github 上,最初基于来自 kernel.org 的 4.5-rc4。)为了使其可以用于一般用途,可能需要避免修复中出现大量不匹配的日志泛滥(也许仅在新值resync_mismatches
< 1000时才记录?)。也可能只记录 forcheck
而不是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 中的奇偶校验不匹配意味着 md 设备的 N-1 个扇区处于危险之中,通过条带单元相互偏移。扇区 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
我猜不是,因为我从所有四个 raid 组件中得到了 4k 个零,并且0^0 == 0
,所以这应该是正确的奇偶校验,对吗?
我在另一处看到提到在 md 中使用扇区地址是 for sync_min
and sync_max
(在 sysfs 中)。 Neil Brown 在 linux-raid 名单上,在回答有关扇区号来自 的故障驱动器的问题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
它位于三个东芝 3TB 驱动器的分区上,以及一个未分区的 WD25EZRS 绿色电源(慢速)驱动器上,我将其替换为另一个东芝驱动器。 (使用mdadm --replace
在线完成,没有冗余间隙。在一份副本之后我意识到我应该在之前和之后检查 RAID 运行状况,以发现问题。就在那时我发现了不匹配。它可能已经存在很长一段时间了,因为我大约一年前发生了一些崩溃,但我没有旧日志,并且 mdadm 似乎默认情况下不会发送有关此的邮件(Ubuntu 15.10)。
我的其他文件系统位于 RAID10f2 设备上,该设备由三个较大 HD 上的早期分区组成(以及 /var/tmp 的 RAID0)。 RAID5 仅用于大容量存储,而不是/home
或/
。
我的驱动器一切正常:所有驱动器上的所有坏块计数器的 SMART 错误计数均为 0,并且短+长 SMART 自检已通过。
这个问题几乎重复,但没有答案:
答案1
长话短说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 是否与我们编写的内容相符。我的 raid 有一个 512k 条带,所以我确保我写了一些对齐的东西以便于匹配,我们在1024*10240
ie上写道0xa00000
。
您的补丁提供了 info 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*3
是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 (确保再次停止/启动阵列),那么零就会回来。看起来不错。
不过,还有一个问题,如果您的条带大小与我的条带大小一样大(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 用户,我会非常感兴趣。我想说,花一点力气绝对值得。你提到的清理可能很有用,我相信一旦你提交补丁,开发人员就会有一些评论,但是MD需要对这些错误更加详细!