我无意中运行了 rm -R /home/。我的 Homefolder 包含几个虚拟机磁盘,这些磁盘此时正在使用中。我还收到错误,提示无法删除某些文件。尽管如此,我还是无法再访问 /home/ 文件夹中的文件。
在寻找解决方案时,我发现我可以尝试使用 cp /proc/PID/fd/12 /target/ 恢复文件。
现在我有点困惑 - 因为虚拟机仍在运行,它可能正在写入我试图恢复的磁盘。
这些磁盘是否会出现不一致的情况?或者您还有其他提示吗?
我感激每一种帮助!
非常感谢!
答案1
给定文件系统上的文件由其索引节点又名索引节点。只要有对此 inode 的引用,无论是在磁盘上(链接为文件名,可以多次存在)还是“在内存中”(打开文件描述符,又称 fd、挂载点、mmaped ......),文件及其数据都会保留在磁盘上。当没有更多引用时,它就会被真正删除,空间也会被回收。当磁盘引用变为 0 时,即使仍有“内存中”的引用,也无法用新名称重新链接它,因为没有内核 API 允许用户例如链接由其 fd 或 inode 值本身引用的 inode,它只能通过文件名获得(除非在适当的文件系统上使用黑暗而危险的魔法: debugfs ln
)。
Linux 内核仍然提供了一些使用伪文件系统访问此文件的功能/proc
。每个打开的文件都显示为指向文件的符号链接。文件的名称是装饰信息(当文件被取消链接时可能会出错),但文件本身应被视为/proc/PID/fd/
这内核所见的实际文件。
因此对于这种情况,只要虚拟机正在运行,用作虚拟机磁盘后端的文件仍然存在,但无法在磁盘上重新链接。可以轻松完成的是使用适当的命令复制它,例如:
cp --sparse=always /proc/PID/fd/12 > backup
。
由于虚拟机正在运行,因此这样做可能会产生不一致的结果:文件系统(文件内部)可能会在复制过程中发生变化,并可能变得不一致和损坏。因此,如果虚拟机管理程序允许,请冻结虚拟机和冻结时不关闭虚拟机的磁盘文件,要么添加对无名文件的新引用,然后停止虚拟机。如果您不想冒险,请在冻结之前添加引用。任何读取文件并持续足够长时间的命令都可以。例如:
$ sleep 99999 < /proc/PID/fd/12 &
[1] 12087
您现在应该验证是否/proc/12087/fd/0
引用同一个... (deleted)
文件。
现在可以冻结甚至停止虚拟机(但之后将无法重新启动)。由于文件系统上不再有活动,因此备份应该是一致的(如果只是冻结,则使用文件系统日志恢复)。如果虚拟机的磁盘文件是“懒惰”配置的并且大部分是空的,则使用cp
with 选项--sparse=always
似乎是一个不错的选择,以使用更少的空间。