LVM文件系统格式丢失

问题描述

某xc项目的OA应用服务器,应用厂商需要对HA高可用进行升级,升级完应用厂商在测试的时候,分别关闭A、B两台服务器进行HA测试,在重启B服务器的时候没问题,在重启A服务器的时候启动不了,排查发现是有一块数据盘文件系统格式丢失,导致该盘无法挂载,mount操作显示unknown filesystem,查看该盘确实没有了文件系统格式。

发生时间:2022.7.2-03:20:36

问题截图1:

问题截图2:

问题排查步骤

1、查看关机日志:

2、关机过程中有lvmetad的error

3、/data目录有挂载报错日志:

备注:

该磁盘是做的单盘raid0,硬raid,一块盘,检查硬raid状态,显示状态正常。

检查message日志,发现只有关机的时候有一段lvm相关的IO报错,了解到关机是使用的poweroff直接关机,怀疑是poweroff直接发送掉电指令导致磁盘故障,badblock扫描了一下磁盘发现没有坏块信息,用户不接受poweroff的解释,需要深入排查。

4、使用命令vgs lvs 发现vg卷组,lv逻辑卷组消失。

通过查看/etc/lvm/archive中的配置文件以及/etc/fatab配置文件可以发现之前做过的配置信息。

问题解决步骤

恢复步骤如下:

1、先直接强制创建pv,(Pvuuid可以在/etc/lvm/archive或backup里配置中找到)
# pvcrate 块设备  --uuid uuid –restorefile 备份vg
#pvcreate /dev/sdb1 --uuid wM5fGI-WdLI-Cnuq-XG1U-3EvV-zOlm-2lphSh --restorefile /etc/lvm/archive/shinemo_lvm_00001-926271509.vg
2、直接恢复lv的是在强制创建pv后,可以恢复的。
#vgcfgrestore -f /etc/lvm/backup/shinemo_lvm shinemo_lvm
3、这个要激活lvm,尽管卷组已经恢复,但是需要将卷组激活才可以使用;以下是卷组激活过程中的尝试:
#vgchange -ay shinemo_lvm
4、挂载卷组

挂载卷组正常,里面的数据也依然存在:

问题原因分析

1、针对问题机器中的重启message日志分析

问题机器从02:43:18开始执行poweroff关机命令,关机时存储的卸载顺序为:

先关闭LVM------>卸载文件系统------>存储下电

在关闭LVM过程中,首先停止LVM-D-Bus服务与Pvscan服务。

268743 Jul  2 02:43:18 push1 systemd[1]: Stopping LVM2 D-Bus service...
268744 Jul  2 02:43:18 push1 systemd[1]: Stopping LVM2 PV scan on device 8:3...

268844行02:43:18 pvscan进程组结束,但并未对8:17设备进行扫描和元数据同步

268844 Jul  2 02:43:18 push1 systemd[1]: Removed slice system-lvm2\x2dpvscan.slice.

269081行02:43:22 卸载LV对应挂载的文件系统卸载成功

269081 Jul  2 02:43:22 push1 systemd[1]: Unmounting /data...

后续开机日志中也未见到有扫描8:17的PV发送。

2、未正常停止shinemo_lvm卷原因分析

根据问题机器日志bokid结果显示/dev/sdb1的LVM标签和UUID丢失,LVM标签位于分区的第2个512B,为LVM元数据,该标签的丢失说明LVM的元数据损坏。

lvm2的数据存储在第二个扇区,而文件系统的读写是从第四个扇区开始读写的(2048Byte),通过文件系统的读写操作是无法修改lvm元数据的。

因此可以产生以下推测:

1)在poweroff关机之前存在直接写块设备的应用写了/dev/sdb1的第二个扇区导致LVM元数据丢失。

2)本次事情lvm使用了缓存机制,即利用内存存储PV及元数据达到性能优化的效果,但lvm元数据通过异步读写,操作系统的脏数据生命周期为30s,poweroff直接发送CPU下电的信号可能会导致LVM元数据未能在内存子系统关闭前完成回写,导致元数据损坏。

问题复现

1、通过重启模拟

虚拟机创建一块新的iscsi磁盘,分区后创建PV lvm-data并在PV上创建lvm,将逻辑卷lvm_data-test格式化为ext4格式挂载到/data目录下,通过dd写一个800M的文件后使用reboot -f 强制关机。

并将挂载方式写入/etc/fatab中开机自动挂载

测试结果:在本地测试5504次PV未出现丢失现象。

2、手动擦除块设备PV信息

在挂载状态下,通过dd if=/dev/zero of=/dev/sdb1 bs=512 count=1 seek=1擦除PV信息

擦除后的/var/log/message中内核报了dd打开了写挂载的设备vdb1,且lvm的pvscan报无法找到PV信息的错。

擦除后由于内存中仍然存在mapper device和taget device的映射表(见dm驱动源码分析)。所以磁盘仍然可以挂载使用。

但当重启后,由于pv丢失lvm元数据,无法根据lvm无法生成mapper device设备导致系统无法启动,通过注释/etc/fstab中lvm_data-test项后,系统可以正常启动。

开机成功后,查看vdb1的UUID、和lv都没有正常生成,这是因为vdb1的UUID已经被擦除,而lvm是根据UUID扫描生成lv的。

通过pvcreate根据备份lvm.vg的数据恢复UUID

小结:通过手动擦除分区的第二扇区可以复现PV丢失现象。

结论

本次poweroff重启后无法挂载磁盘的原因为shinemo_lvm PV元数据丢失造成的,在故障后通过备份的元数据重建VG后,系统lvm恢复正常。

故,在此次事情环境中,逻辑卷创建时间为2021年6月18日,开机时间为2021年6月16日,关机时间为2022年7月2日。

通过重启5504次未能复现现场现象,基本排除PV丢失是由重启导致的,而是在系统重启前就已经丢失,由于内存中仍然存在mapper device和target device的映射表,因此不会影响系统使用(见抹除PV信息)。

通过手动擦除PV信息(dd if=/dev/zero of=/dev/sdb1 bs=512 count=1 seek=1),然后重启能够成功复现此现象,因此推测该问题是直接写块设备造成的

通过遍历message-20220321到message-20220702日志,并未发现在有直接对挂载状态的块设备/dev/sdb1的操作(见write源码分析,如果存在直接写块设备,那么日志中会存在VFS相关日志),结合系统开机时间为2021年6月16日,早期日志丢失,无法确认PV丢失的具体时间。

结论:

本次事件原因为sdb1的PV信息丢失造成的,PV丢失后内存中存储的mapper device和target device的映射表仍然可以支持系统运行。但重启后内存中的数据刷新,没有PV信息l,lvm无法生成mapper device,导致系统无法启动。

源码分析

结合源码分析PV丢失原因,主要从物理卷映射为逻辑卷的底层源码,和块设备直接操作的栈进行分析。

块设备写操作源码分析

1、要修改PV信息需要直接操作块设备,在arm64内核中通过write系统调用陷入内核态,直接操作块设备的主要的调用栈如下:

write
__arm64_sys_write
ksys_write
vfs_write
__vfs_write
new_sync_write
blkdev_write_iter
__generic_file_write_iter
generic_perform_write
blkdev_write_begin
blkdev_write_end
__block_commit_write.isra.11
__set_page_dirty

首先通过write系统调用陷入内核态,并在vfs_write中将用户态缓存根据不同文件系统的file_operation写入对应设备文件。

在打开块设备描述符(blkdev_open)时调用blkdev_get获取文件描述符,当磁盘已经以可写方式打开时(如可写mount)blkdev_get中会对直接打开块设备描述符的操作发出警告(VFS: Open an write opened block device exclusively),因为这样可能会导致文件系统损坏。

2、mapper device映射源码分析

mapper_device由 lvm通过ioctl陷入md驱动生成,在lvm创建完成后,通过vgchang -ay按照lvm配置文件中UUID寻找device target生成mapper_device,主要栈如下

vgchange
process_each_vg
vg_read
vg_read_internal
udev_device_get_devlinks_list_entry
dm_tree_preload_children
dm_ctl_ioctl
dev_create
dm_create
device_add_disk_no_queue_reg
sysfs_create_link

在mapper_device的创建过程中,主要是完成三件事

  1. 向内核申请不可回收的slab 缓存,用于存放mapped device结构体,并将该mapped device作为磁盘块设备注册到内核中。
  2. 通过blk_queue_make_request函数注册该mapped device对应的请求队列dm_request
  3. 创建
  4. 调用table_load构建mapper device和target device的映射表,映射表同样会存储在内存当中。

Device mapper本质功能就是根据内存中的映射关系和将I/O请求从逻辑设备mapper device转发相应的target device上,针对lvm则是将一个或多个物理卷映射为逻辑卷,在device mapper和映射表创建成功后,用户只需要对逻辑卷进行操作,内核会根据内存中device mapper的映射表将请求下发至真实设备。

问题相关链接

https://www.cnblogs.com/alisapine/p

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值