一、背景
修机师傅运气不错,有时候还能收到些“奇奇怪怪”的问题,话说df -h返回值为负,是啥情况,上个图:
检查挂载点下,也没有特别异常的文件,而且业务还运行正常。检查内核日志,发下xfs有报错:
重启故障虚拟机,也还是有这个现象 。在关机状态下,克隆了一台做测试,以下操作,基于克隆的虚拟机。
二、修复与分析
1、进入救援模式,查看挂载点显示为负值:
2、执行xfs_repair /dev/mapper/centos-root,然后再次挂载正常:
从xfs_repair修复的结果看,有识别到一些异常,并且成功修复了;而修复之后,再次挂载空间使用也正常。
结合日志和操作分析是xfs文件系统异常导致,后面在redhat kb库也找到了类似案例,同步分享下。
3、进一步分析根因
Root Cause
- In this case, the command the strace of the df command provided a value of f_bfree, 37345930, which is larger than the value of f_blocks, 34216732. Based on statfs(2) man page, we see the second parameter is a struct which the kernel populates, with the following member definitions:
Raw
struct statfs { long f_type; /* type of file system (see below) */ long f_bsize; /* optimal transfer block size */ long f_blocks; /* total data blocks in file system */ long f_bfree; /* free blocks in fs */ long f_bavail; /* free blocks avail to non-superuser */ long f_files; /* total file nodes in file system */ long f_ffree; /* free file nodes in fs */ fsid_t f_fsid; /* file system id */ long f_namelen; /* maximum length of filenames */ };- statfs is part of the linux VFS, so each file system will have it's own implementation. In this case, the file system was ext3, which populates the two struct fields of interest in fs/ext3/super.c via:
Raw
fbuf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead; buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);- Since both values are maintained by the file system, some form of filesystem corruption seemed likely.
Diagnostic Steps
- Run strace to determine if the kernel is handing back bad data or df mishandling it
- In particular, look at the values of f_bfree and f_blocks
- If b_free excedes b_blocks, the kernel is providing bad data
Raw
# strace -e trace=statfs,statfs64 df /dev/cciss/c0d0p1 >/dev/null statfs("/", {f_type="EXT2_SUPER_MAGIC", f_bsize=4096, f_blocks=34216732, f_bfree<br />=37345930, f_bavail=35579785, f_files=35323904, f_ffree=35180816, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0参考上述kb,当文件系统的f_free大于f_blocks时,会出现负值,我这边的环境:
这个值出现异常,也就是前面xfs报错相关。
三、总结
df -h返回负值,是因为文件系统元数据f_free大于f_blocks导致,解决方案主要也是通过文件系统修复来处理:
1、卸载并检查文件系统
对于ext3/ext4文件系统,使用e2fsck -fvy /dev/centos/root来修复
对xfs文件系统,使用xfs_repair命令
2、如果无法卸载文件,则进救援模式,并参考上面步骤处理。
3、如果文件系统仍显示负值,则考虑是否空间不足,尝试进行文件系统扩容。