一次调查centos 6.2上xfs文件系统宕机后文件数据丢失的经历

阿里云每天都会接到大量的客户工单,工单问题千奇百怪,不少问题调查起来颇费周折。下面的这个问题很有意思,一开始我们以为是ECS的bug,导致用户数据丢失,吓出一身冷汗,后来发现问题出在操作系统。一次次与底层系统的交手,慢慢的让阿里云的产品变得更加透明。

 
今天接到用户工单,反馈说他的云服务器发生了宕机迁移,奇怪的是迁移后部分文件长度变成0了,但是之前升级应用的时候确认过这些文件肯定是正常的。粗看现象确实比较奇怪,根据用户提供的操作,可以抽象为向xfs文件系统上写了一些文件数据,然后系统宕机。系统恢复后文件长度为0。 据此,我们编写了一个复现脚本程序来模拟此问题。脚 本如下:

 

#!/bin/bash

dst=${1}

for ((i=1;i<=10000;i++)); do tmpfile=${dst}/file.$(date ‘+%T’).${i} echo ${tmpfile} dd if=/dev/zero of=${tmpfile} bs=1M count=8 &>/dev/null
done
 

该脚本通过dd(1)命 令在 指定的目录下创建10000个8M大 小的文件用来模拟用户的行为。在centos 6.2上(2.6.32-220.23.1) 上运行此脚本:
 

$ ./xfs-bug.sh ${XFS_MNT} # XFS_MNT为xfs文 件系统的挂载点
 

在持续运行一段时间,比如拷贝到2000+个 文件的时候我们强制系统重启(sudo sh -c “echo b >/proc/sysrq-trigger”)。在 重启 后我们会看到如下结果:
 

$ ls -l ${XFS_MNT} | less
total 15785984
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:23 file.14:23:01.1
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:23 file.14:23:01.10
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:23 file.14:23:01.11

-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:24 file.14:24:35.1240
-rw-rw-r– 1 wenqing.lz wenqing.lz 45056 Mar 13 14:24 file.14:24:35.1241
-rw-rw-r– 1 wenqing.lz wenqing.lz 6373376 Mar 13 14:24 file.14:24:35.1242
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:24 file.14:24:35.1243
-rw-rw-r– 1 wenqing.lz wenqing.lz 6311936 Mar 13 14:24 file.14:24:35.1244

-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:24 file.14:24:42.1304
-rw-rw-r– 1 wenqing.lz wenqing.lz 28672 Mar 13 14:24 file.14:24:42.1305
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:24 file.14:24:42.1306
-rw-rw-r– 1 wenqing.lz wenqing.lz 77824 Mar 13 14:24 file.14:24:42.1307
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:24 file.14:24:42.1308
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:24 file.14:24:43.1309

-rw-rw-r– 1 wenqing.lz wenqing.lz 4198400 Mar 13 14:25 file.14:25:17.1596
-rw-rw-r– 1 wenqing.lz wenqing.lz 4198400 Mar 13 14:25 file.14:25:17.1597
-rw-rw-r– 1 wenqing.lz wenqing.lz 0 Mar 13 14:25 file.14:25:17.1598
-rw-rw-r– 1 wenqing.lz wenqing.lz 0 Mar 13 14:25 file.14:25:17.1599

-rw-rw-r– 1 wenqing.lz wenqing.lz 0 Mar 13 14:26 file.14:26:21.2146
-rw-rw-r– 1 wenqing.lz wenqing.lz 0 Mar 13 14:26 file.14:26:21.2147
-rw-rw-r– 1 wenqing.lz wenqing.lz 0 Mar 13 14:26 file.14:26:21.2148
-rw-rw-r– 1 wenqing.lz wenqing.lz 0 Mar 13 14:26 file.14:26:21.2149
 

可以看到,很多已经拷贝了2、3分钟的文件的文件长度是不正确的,而很多文件的长度均为0。这一结果是不符合预期的。即操作系统在 用户没有执行sync(1)命令的情况下,会默认将超过30s的脏数据写回磁盘。而这里很多长度不对的文件的创建时间已经超过这 一时 间。 说明此脚本可以基本复现用户的问题,并且2.6.32-220.23.1内核上的xfs确实存在缺陷。
 
根据搜索网上的相关信息,可以看到redhat针 对2.6.32-220内核上的xfs曾经修复过一个类似错误(http://rhn.redhat.com/errata/RHSA-2012-1401.html)。 我把相关说明粘贴在此:
 

* Under certain circumstances, a system crash could result in data loss on
XFS file systems. If files were created immediately before the file system
was left to idle for a long period of time and then the system crashed,
those files could appear as zero-length once the file system was remounted.
This occurred even if a sync or fsync was run on the files. This was
because XFS was not correctly idling the journal, and therefore it
incorrectly replayed the inode allocation transactions upon mounting after
the system crash, which zeroed the file size. This problem has been fixed
by re-instating the periodic journal idling logic to ensure that all
metadata is flushed within 30 seconds of modification, and the journal is
updated to prevent incorrect recovery operations from occurring.
(BZ#856685)

 
大意是说在某些特定条件下或者系统宕机后会造成xfs文件系统上文件数据的丢失(文件长度为0)。为了验证此问题是否在后续版本中 已经得到修复,我们测试了最新的2.6.32-358.14.1内核。重复同样的测试,我们得到了如下的 结 果:
 

$ ls -l ${XFS_MNT} | less
total 15982592
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:39 file.14:39:11.1
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:39 file.14:39:11.10
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:39 file.14:39:11.11

-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:40 file.14:40:16.1019
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:40 file.14:40:16.1020
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:40 file.14:40:16.1021
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:40 file.14:40:16.1022

-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:41 file.14:41:09.1513
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:41 file.14:41:09.1514
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:41 file.14:41:09.1515

-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:42 file.14:42:09.2067
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:42 file.14:42:09.2068
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:42 file.14:42:09.2069
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:42 file.14:42:09.2070

-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:42 file.14:42:22.2187
-rw-rw-r– 1 wenqing.lz wenqing.lz 8388608 Mar 13 14:42 file.14:42:22.2188
-rw-rw-r– 1 wenqing.lz wenqing.lz 0 Mar 13 14:42 file.14:42:22.2189
 

可以看到,只有最后一小部分文件的长度为0。 这一结果是符合预期的。可以说明在2.6.32-358内核中, 此问 题已经得到修复。 为了确认358内核上xfs确实修复了此问题,我们对比了358和220内 核的changlog。 对比中我们发现了几个和XFS相关的补丁。 这里一并列举出来:
 
xfs: log the inode in ->write_inode calls for kupdate
xfs: log all dirty inodes in xfs_fs_sync_fs
 

根据xfs邮件列表里的 记 录,这两个补丁是作为一个整体提交给社区的。我们知道Linux内 核 的脏数据回写是由内核 writeback机制来保证的。第 一个补丁 的作用是修复xfs在Linux内 核尝试回写超过30s的 脏数据时的一个bug。即在此补丁 之前,有可能在某些条件下xfs无法正确回写超过已经超过30s的 脏数据。此补丁是在xfs_fs_write_inode()函 数中 判 断wbc->for_kupdate变量。而这 一变量在Linux kernel尝试刷新超过30s脏 数据时会被置为1。 第二个补丁修复的则是由于Linux Kernel中writeback路 径的修改引起的xfs回写行为的不正常。根据描述,由于writeback路径的修改造成 older_than_this变量的检查更加严格,由此造成有可能被置脏的inode得不到回写。这里的 older_than_this恰恰是系统回写超过30s脏 数据时判断脏数据时间的标志。
 

综上可以基本确认这次用户文件数据在宕机后的丢失是由于xfs文件系统中的一个缺陷造成的。
 

(本文作者是阿里云核心系统团队的文卿。)

上一篇:微信小程序 HelloWorld


下一篇:VC2015创建多线程