![有没有办法以原子方式将文件和目录从 tempfs 移动到 eMMC 上的 ext4 分区](https://linux22.com/image/135873/%E6%9C%89%E6%B2%A1%E6%9C%89%E5%8A%9E%E6%B3%95%E4%BB%A5%E5%8E%9F%E5%AD%90%E6%96%B9%E5%BC%8F%E5%B0%86%E6%96%87%E4%BB%B6%E5%92%8C%E7%9B%AE%E5%BD%95%E4%BB%8E%20tempfs%20%E7%A7%BB%E5%8A%A8%E5%88%B0%20eMMC%20%E4%B8%8A%E7%9A%84%20ext4%20%E5%88%86%E5%8C%BA.png)
我们有基于 beaglebone black 的定制板,配有 256MB RAM 和 4GB eMMC。主板运行Linux内核4.9
我们遇到这样的情况:我们创建一个文件,tempfs
然后在验证后,我们必须将其移动到 eMMC 的 ext4 分区。仅归档一个certificate
在某些情况下,我们在一个目录中有多个证书,因此我们必须将整个目录从 tempfs 移动到 eMMC 上的 ext4 分区。
所以我们担心的一个问题就是atomicity
(mv
移动)操作。
根据rename
系统调用,Linux 手册页重命名文件是一个原子操作。
http://man7.org/linux/man-pages/man2/rename.2.html
但是我们不确定重命名操作是否涉及在两个文件系统之间移动文件,原子性是否仍然可用。所以问题是将文件从原子移动tmpfs
到ext4
原子吗?
显然,一种可能的解决方案是将文件保存在同一分区上的不同文件夹中(显然在同一文件系统上)并使用mv
.对于使用以下重命名方法的目录
SRC_dir --> TMP_DEST_dir
DEST_dir --> BAK_DEST_dir
TMP_DEST_dir --> DEST_dir
delete BAK_DEST_dir
有什么替代方案的建议吗?
编辑
在我得到回复后,我尝试遵循板上的测试代码,
#include <stdio.h>
#include <errno.h>
int main()
{
int retcode = 0;
system("touch /tmp/rename_test");
retcode = rename("/tmp/rename_test", "/home/fs_rename_test");
if ( retcode < 0) {
printf("errno : %d\n",errno );
perror("Error occurred while renaming file");
return 1;
}
return 0;
}
返回以下输出。并确认重命名不适用于跨文件系统。
errno : 18
Error occurred while renaming file: Invalid cross-device link
答案1
将文件从 移动到
tmpfs
是ext4
原子的吗?
不可以。这样的重命名仅在文件系统内有效。手册页rename(2)
明确提到了如果尝试跨挂载点重命名则会返回的错误:
EXDEV
旧路径和新路径不在同一个安装的文件系统上。
跨文件系统的移动需要通过复制和删除的组合来完成。mv
如果不起作用,它将为您执行此操作rename()
,但在这种情况下它不会是原子的。
解决这个问题的简单方法确实是首先将文件复制到同一文件系统上的临时位置。一般来说,最简单的方法是将临时文件放在与最终目标相同的目录中,因为这是唯一保证位于同一文件系统上的位置。当然,这要求处理该文件的任何进程都将有一些逻辑来根据其名称忽略临时文件。
粗略地说,这样的事情应该适用于一个文件:
cp /src/filename /dst/filename.tmp &&
mv /dst/filename.tmp /dst/filename &&
rm /src/filename
请注意,您描述的过程目录本质上是这样的:
cp -r /src/dir /dst/dir.tmp &&
mv /dst/dir /dst/dir.bak &&
mv /dst/dir.tmp /dst/dir &&
rm -r /dst/dir.bak
这还不错,但是不是原子。两次运行mv
(或调用rename()
)之间有一段时间,此时/dst/dir
不存在。这可以通过通过符号链接访问目录来解决,因为该链接可以通过重命名自动替换。