on ext4 renameat2 fails in conjunction with RENAME_NOREPLACE, if the target file is not present
renameat2(AT_FDCWD, "rename-test-a", AT_FDCWD, "rename-test-c", RENAME_NOREPLACE) = -1 EINVAL (Invalid argument)
if the target file is present, functionality is ok
works with brtfs and xfs
Created attachment 260359 [details]
Test case showing the problem
A test case, run with a.out <srcfile> <dstfile>
I'm hit by this on 4.10 a well (the default kernel on Ubuntu 16.04).
I attached a full test case showing.
> [estan@newton renameat2tc]$ gcc renameat2.c
> [estan@newton renameat2tc]$ touch foo
> [estan@newton renameat2tc]$ ./a.out foo bar
> Invalid argument
> [estan@newton renameat2tc]$ uname -a
> Linux newton 4.10.0-37-generic #41~16.04.1-Ubuntu SMP Fri Oct 6 22:42:59 UTC
> 2017 x86_64 x86_64 x86_64 GNU/Linux
> [estan@newton renameat2tc]$ mount | grep " / "
> /dev/sda1 on / type ext4 (rw,noatime,discard,errors=remount-ro,data=ordered)
The reason I discovered it was that Qt recently started using this syscall, which in turn made Qt Creator (a Qt application) fail to write its config files.
Martin: can you confirm you did see these issues on 4.4 and 4.11? Elvis is reporting he did not see the issue on 4.4.
By any chance, are you also on Ubuntu?
Martin: I've just discovered that I only see this problem when on my eCryptfs encrypted home directory, not when testing in e.g. /tmp (unencrypted). Are you also using eCryptfs?
So I guess I'm hitting this: https://github.com/torvalds/linux/blob/master/fs/ecryptfs/inode.c#L592
Seems rename flags are not supported on ecryptfs, plain and simple?
Here's the patch that added the if (flags) return EINVAL; for ecryptfs:
So I guess it's just expected that it won't work on ecryptfs.
Though I wonder if that is correct, or if it was hastily added by mistake for ecryptfs as part of that mass porting to rename2.. Maybe it would just work if ecryptfs_rename simply forwarded the flags to vfs_rename without checking them..? Someone who knows the code will have to answer.
Scratch that, it's obviously not that easy.
No, it seems that non-local filesystems need specific code to guarante RENAME_NOREPLACE, so the EINVAL error is legitimate.
I've confirmed that the test case works just fine on plain ext4, using the 4.13 based kernel. I've also confirmed that it works just fine if you use ext4 encryption. (I suggest that Ubuntu users file a feature request bug to Ubuntu to ditch ecryptfs and switch to ext4 encryption.)
I can also confirm that ecryptfs != ext4, and that discussing this here has approximately zero chance of it being noticed by the ecryptfs maintainer. Since Tyler works at Canonical, filing a Launchpad bug is most likely to get someone to look at it.
For the record, I'm applying a fix to the Qt code, since the error is legitimate for non-local fs: https://codereview.qt-project.org/209385
Indeed, I'll file an LP bug and try to ping Tyler. Who knows, perhaps they're already planning to switch to encrypted ext4 (thanks for testing that Ted).
And thanks to Thiago for being so quick with the Qt fix (I ran into this behavior by way of Qt).
Michael Halcrow (the original author of ecryptfs, and who has jokingly referred to his work on ext4 encryption as his apology for ecryptfs :-) and I have talked to Tyler about Ubuntu switching to ext4 encryption. This is really going to be a matter of prioritizing work at Canonical; so user feature requests (especially requests from paying users :-) would be helpful.