linux rename embedded ext4 tmpfs – How to Atomically Move File from tmpfs to ext4 on eMMC

embeddedext4linuxrenametmpfs

We have beaglebone black based custom board with 256MB RAM and 4GB eMMC.
Board runs Linux kernel 4.9

we are running into a situation where we create a file in tempfs and then after validation, we have to move it to the ext4 partition of eMMC. File nothing but a certificate

in some situations, we have multiple certs in a directory so we have to move the whole directory from tempfs to the ext4 partition on eMMC.

So one of the problems we are worried about is atomicity of mv(move) operation.

As per rename system call Linux man page renaming file is an atomic operation.
http://man7.org/linux/man-pages/man2/rename.2.html

However we are not sure if rename operation involves moving files between two filesystems, atomicity is still available or not. So question is
Is moving file from tmpfs to ext4 atomic?

Obviously, one possible solution is to keep files in a different folder on the same partition (on same filesystem obviously ) and rename it using mv.
For directory using below approach of renaming

SRC_dir  --> TMP_DEST_dir
DEST_dir --> BAK_DEST_dir
TMP_DEST_dir --> DEST_dir
delete BAK_DEST_dir

Any suggestion for alternatives ?

EDIT
After i got reply i tried following test code on the board,

#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;
}

Which returned following output. And confirmed that rename doesn't work cross file-system.

errno : 18
Error occurred while renaming file: Invalid cross-device link

Best Answer

Is moving file from tmpfs to ext4 atomic?

No. Renames as such only work within a filesystem. The manual page for rename(2) explicitly mentions the error that is returned if trying to rename across mount points:

EXDEV oldpath and newpath are not on the same mounted filesystem.

Moves across file systems need to be done as a combination of a copy and a delete. mv will do this for you if the rename() doesn't work, but it will not be atomic in that case.

The simple way to work around that would indeed be to first copy the file to a temporary location on the same filesystem. In general, it's simplest to place the temporary file in the same directory as the final destination, since that's the only place that's guaranteed to be on the same filesystem. Of course that requires that any process working on the files there will have some logic to ignore the temporary based on its name.

Roughly, something like this should work for one file:

cp /src/filename /dst/filename.tmp &&
mv /dst/filename.tmp /dst/filename &&
rm /src/filename

Note that the process you describe for a directory is essentially this:

cp -r /src/dir /dst/dir.tmp && 
mv /dst/dir /dst/dir.bak    &&
mv /dst/dir.tmp /dst/dir    &&
rm -r /dst/dir.bak

Which is not bad, but is not atomic. There's a moment of time between the two runs of mv (or calls to rename()), when /dst/dir does not exist. That could be worked around by accessing the directory through a symlink, since the link can be atomically replaced with a rename.

Related Question