我相信,如果您将mv
文件从 ext4 分区复制到其自身,则通过更新目录条目并保持 inode 相同,可以在恒定时间内立即完成此操作。
相反,有时我观察到整个(30GB)文件被复制,然后原始文件被删除。
为什么会发生这种情况?
答案1
该mv
命令在内部调用rename()
,并且在单个文件系统挂载点内重命名仅更改名称条目(在同一目录中或将名称从一个目录移动到另一个目录)。
但是,在某些情况下,rename()
将返回EXDEV
(“跨设备链接错误”)给调用者,在这种情况下,mv
将回退到新位置复制文件(或整个目录树),并删除位于以下位置的文件/目录:之后的旧位置。
rename()
返回的最常见原因EXDEV
是调用的源目录和目标目录rename()
位于不同的文件系统中,并且同一文件系统的安装点可能不同。如果项目配额正在使用(在源文件/目录和目标目录上运行“lsattr -p”进行检查)并且源/目标使用不同的项目 ID,则EXDEV
也会返回到用户空间,并且需要mv
创建一个复制目标处的文件/目录树并更改 projid 以匹配新的父级。
源目录和目标目录上的不同项目 ID 触发副本而不是直接更新项目 ID 的原因rename()
是,如果存在需要 projid 的整个目录树,这可能会变得过于复杂,无法在内核中进行原子处理被改变。在这种情况下,可能有数千或数百万个文件需要更新。也就是说,projid 更新可以rename()
重命名时直接完成单个文件,但这在 ext4 代码中尚未实现。
如果您知道涉及项目 ID,则可以通过“预先更改”源文件/目录树的项目 ID 以匹配目标 projid 来避免大文件或目录树的“后备副本”。在使用“mv”之前运行“chattr -R -p <target_projid> ”,使源和目标projid相同,然后rename()
应该可以工作而不返回EXDEV
,并且不会触发复制。