我有一个在 tmpfs 上有 / 的系统。大多数 / 子目录都挂载了 aufs,将读写根文件系统与只读基本文件系统覆盖(系统从只读介质启动)。以前,我使用 unionfs 而不是 aufs。它一直运行正常,直到最近 tmpfs 开始填满。我不确定是什么引发了这种变化。可能是 unionfs 到 aufs 的更改、内核升级或系统及其访问文件系统方式的一些更改。
不管怎样,看起来是 tmpfs 的行为出了问题。
尽管系统不应该向 tmpfs 写入大量数据,但其中相当一部分已被使用:
# df -m /
Filesystem 1M-blocks Used Available Use% Mounted on
tmpfs 200 50 151 25% /
尽管:
# du -smx /
2 /
这是我的测试系统,基本上什么都没做。当使用率很快超过 90% 时,生产系统就会出现磨损,然后系统就会崩溃。
我怀疑这些是已删除的文件仍然打开,但是:
# lsof | grep deleted
什么也没显示。
另一个想法是,/ 上的某些文件被安装在其上的文件系统屏蔽了,所以我尝试了这个:
# mount --bind / /mnt
# du -sm /mnt
2 /mnt
但 48MB 的丢失依然没有踪影。
我怎样才能找出是什么占用了我的 tmpfs 文件系统?
系统信息:
# uname -rm
3.4.6 i686
更新:我已经尝试了内核 3.4.17 和 3.6.6 – 没有变化。
答案1
在 aufs 维护者 Junjiro Okajima 的帮助下,我自己解开了这个谜团。
调试问题的第一步是以一种可控的方式重现问题。我花了一些时间(现在我想知道为什么花这么多时间)才发现,问题发生在通过 aufs 写入和删除文件时。
重现问题
创建挂载点:
# cd /tmp
# mkdir rw
# mkdir mnt
挂载 tmpfs:
# mount -t tmpfs none /tmp/rw
挂载 aufs,用 /tmp/rw 覆盖 /usr:
# mount -t aufs -n -o "br:/tmp/rw:/usr" none "/tmp/mnt"
现在我可以看到 /tmp/mnt 下的 /usr 内容:
# ls /tmp/mnt
bin games include lib lib64 local sbin share src
我感兴趣的是下面 tmpfs 上的已用/可用空间:
# du -sk /tmp/rw
0 /tmp/rw
# df /tmp/rw
Filesystem 1K-blocks Used Available Use% Mounted on
none 1031128 24 1031104 1% /tmp/rw
/tmp/rw 中没有文件,但分配了 24 个块。仍然不是大问题。
我可以将文件写入aufs,它将被存储在/tmp/rw中的tmpfs上:
# dd if=/dev/zero of=/tmp/mnt/test bs=1024 count=100
100+0 records in
100+0 records out
102400 bytes (102 kB) copied, 0.000343903 s, 298 MB/s
# du -sk /tmp/rw
100 /tmp/rw
# df /tmp/rw
Filesystem 1K-blocks Used Available Use% Mounted on
none 1031128 128 1031000 1% /tmp/rw
注意使用情况统计数据是如何变化的。du
显示增加了 100kB,正如预期的那样,但是输出中的“已使用”值df
增加了 104 个块。
当我删除该文件时:
# du -sk /tmp/rw
0 /tmp/rw
# df /tmp/rw
Filesystem 1K-blocks Used Available Use% Mounted on
none 1031128 28 1031100 1% /tmp/rw
四个区块丢失。
当我重复dd
和rm
命令几次时,我得到:
# df /tmp/rw
Filesystem 1K-blocks Used Available Use% Mounted on
none 1031128 36 1031092 1% /tmp/rw
越来越多的 tmpfs 块消失了,我不知道它去了哪里……
我做了同样的事情 –dd
直接rm
在 /tmp/rw 上这样做不会丢失任何东西。卸载 aufs 后,tmpfs 上丢失的空间被恢复了。所以,至少我知道这是 aufs 的问题,而不是 tmpfs 的问题。
发生了什么
知道该归咎于什么之后,我在 aufs-users 邮件列表上描述了我的问题。我很快就收到了第一批答复。JR冈岛的帮助我解释丢失的 tmpfs 块发生了什么。
确实,这是一个已删除的文件。它没有被显示出来,lsof
因为/proc/<pid>/*
该文件没有被任何用户空间进程打开或映射。该文件,即“xino 文件”,是 aufs 的外部 inode 编号转换表,由内核 aufs 模块内部使用。
可以从 sysfs 中读取文件路径:
# cat /sys/fs/aufs/si_*/xi_path
/tmp/rw/.aufs.xino
但由于文件已被删除,因此无法直接看到:
# ls -l /tmp/rw/.aufs.xino
ls: cannot access /tmp/rw/.aufs.xino: No such file or directory
但是,可以从 debugfs 中读取有关其大小以及其他特殊 aufs 文件大小的信息:
# for f in /sys/kernel/debug/aufs/si_8c8d888a/* ; do echo -n "$f: " ; cat $f ; done
/sys/kernel/debug/aufs/si_8c8d888a/xi0: 1, 32x4096 132416
/sys/kernel/debug/aufs/si_8c8d888a/xi1: 1, 24x4096 626868
/sys/kernel/debug/aufs/si_8c8d888a/xib: 8x4096 4096
/sys/kernel/debug/aufs/si_8c8d888a/xigen: 8x4096 88
详细信息请参见aufs 手册页。
解决方案
可以通过以下方式手动截断“xino 文件”:
# mount -o remount,itrunc_xino=0 /tmp/mnt
在挂载 aufs 时可以使用 trunc_xino 选项来请求自动 xino 文件截断:
# mount -t aufs -n -o "br:/tmp/rw:/usr,trunc_xino" none "/tmp/mnt"
我仍然不知道它如何影响文件系统性能,或者这是否真的能解决我的生产中的 tmpfs 空间不足问题......但我已经学到了很多东西。
答案2
我曾见过这种情况:文件被删除,但进程仍保留着该文件,这意味着空间直到进程重新启动后才会释放。我在 Apache 日志文件中也见过这种情况。它似乎继续写入现已删除的日志文件,空间直到重新启动后才会被清除。
要找出哪个进程可能保留了已删除的文件,您可以尝试重新启动每个进程,看看是否能清除空间。如果能,您就找到了罪魁祸首。
高血压