我的一个托管服务器出现了一些 XFS 问题。上次崩溃后,我的一些 RRD 文件夹被损坏了。
例如(抱歉,这是法语):
# rm *
rm: impossible de supprimer « create_rrd.sh »: La structure a besoin d'un nettoyage
rm: impossible de supprimer « old »: est un dossier
rm: impossible de supprimer « tcgraph.log »: La structure a besoin d'un nettoyage
rm: impossible de supprimer « tcgraph.rrd »: La structure a besoin d'un nettoyage
正常的做法是重启单用户系统,或者使用 live cd,然后在 /dev/sda 上运行 xfs_repair。不幸的是(这太简单了),托管公司提供了一个在 live cd 上重启的选项,但这个选项不起作用。而且访问数据中心也不行。
看来我根本无法触及 inode,每次我都会收到“结构需要清理”的消息。
所以,问题是:有人知道手动修复/修复 XFS 文件系统的方法吗? 有没有什么低级 XFS 操作工具可以帮忙?
答案1
最简洁的答案是不。
更长的答案是非常非常迷人尝试将所有内容复制到 tmpfs ramdisk,切换至该磁盘,然后卸载硬盘文件系统并在修复驱动器文件系统时完全从 RAM 运行。
我不是第一个想到这一点的人,我发现此主题但没有关于该计划是否真的奏效的信息。由于该计划的目的是清除驱动器,因此他们没有费心卸载它。
为此,创建一个目录,mount -t tmpfs none /some/directory
然后开始用系统重要部分的副本填充它(sshd、mount、umount、xfs 工具、shell 和运行它所需的所有库,可能还需要所有 /etc,最后是 init...chroot jail 创建脚本会在这里有所帮助,大约 4GB 的 RAM 也会有所帮助。在其中挂载 proc 的副本,如果您使用 devfs,也请挂载 devfs 的副本。使用 /etc/ssh/sshd_config 的副本,设置 sshd 以在不同的端口上启动。chroot 到您的 ramdisk 并确保一切正常并且没有缺少的库,然后在 ramdisk 中启动 sshd(在备用端口上),以便它在那里 chrooted。检查您是否可以通过 ssh 进入它(这可能还需要将您的 /home 目录复制到那里)(并打开您可能拥有的任何防火墙上的端口)。
现在,魔法开始了:你不需要 chroot 到那个 tmpfs,而是需要找到一个名为枢轴根.它生命的唯一目的就是呼唤枢轴根()。它在 Debian 上的 util-linux 中。pivot_root() 的目的本质上是立即 chroot 所有进程。最初用于将 / 从 initrd ramdisk 映像移动到实际驱动器,如果此方法有效,您将从实际驱动器移动到 ramdisk 映像。因此,假设您已将mkdir /mnt/tmpfs; mount -t tmpfs none /mnt/tmpfs
所需的所有内容复制到其中,下一步是mkdir /mnt/tmpfs/oldroot; pivot_root /mnt/tmpfs /oldroot
(如果复制内容时空间不足,请卸载 /mnt/tmpfs 并再次安装它,这次使用,-o size=...
因为默认情况下只允许一半的内存。)
最后一步是卸载 /oldroot。您需要卸载 /oldroot/sysfs /oldroot/proc 等(检查 /proc/mounts)。如果仍然收到“文件系统繁忙”的提示,您可以尝试强制卸载,或者至少通过查看和终止ls -l /proc/*/cwd /proc/*/fd/ | grep /oldroot/
仍然引用它的所有内容来追踪所有打开了文件的内容(这可能包括未 chroot 的 ssh 服务器。在开始终止任何内容之前,请确保您已登录到该备用 sshd)。显然不要终止进程 1(init)。如果无法在 init 运行时强制卸载,则需要使用chroot /oldroot /sbin/telinit u2
(2=您当前所处的运行级别,否则 init 可能会终止所有内容,然后您重新启动并重新开始) 通过运行 ramdisk 中的“新”init 来让 init “升级”。您需要将其 chroot 到 /oldroot 才能使其使用 /oldroot/dev/initctl(ramdisk /dev/initctl 不一样)(请注意,telinit 将使用 [/oldroot]/dev/initctl 与已 pivot_rooted 到 ramdisk 的现有 init 进程进行通信,因此它启动的 init 将位于 ramdisk 上,而不是 /oldroot 上)。
我不打算在生产服务器上尝试这个。也许这个周末我会在家里尝试一下。