unlink(nonexistent): EROFS or ENOENT?
Hello.
Just noticed that at least on ext4, unlinking a non-existing file from a read-only filesystem results in EROFS instead of ENOENT. I'd expect it return ENOENT - it is more logical, at least in my opinion.
For one, (readonly) NFS mount returns ENOENT in this case.
Thanks!
/mjt
29.05.2011 20:08, Michael Tokarev пишет:
Quoted 7 lines
Hello.
Just noticed that at least on ext4, unlinking a non-existing file from a read-only filesystem results in EROFS instead of ENOENT. I'd expect it return ENOENT - it is more logical, at least in my opinion.
http://pubs.opengroup.org/onlinepubs/009695399/functions/unlink.html
this case is quite clear:
[EROFS]
The directory entry to be unlinked
is part of a read-only file system
Ie, the entry is a _part_ of a file system, so it should be _existing_ entry to start with.
Quoted 4 lines
For one, (readonly) NFS mount returns ENOENT in this case.
Thanks!
/mjt
Quoted 10 lines · Michael Tokarev
Hello.
Just noticed that at least on ext4, unlinking a non-existing file from a read-only filesystem results in EROFS instead of ENOENT. I'd expect it return ENOENT - it is more logical, at least in my opinion.
For one, (readonly) NFS mount returns ENOENT in this case.
Um, it doesn't for me. Testing on v3.0-rc1:
# ls /test/foo; rm /test/foo ls: cannot access /test/foo: No such file or directory rm: cannot remove `/test/foo': No such file or directory # ls /test/null; rm /test/null /test/null rm: cannot remove `/test/null': Read-only file system # grep test /proc/mounts /dev/vdb /test ext4 ro,relatime,user_xattr,barrier=1,data=ordered 0 0
- Ted
Thank you for the answer. I thought noone will reply... ;)
Quoted 9 lines · Ted Ts'o
Quoted 8 lines · Michael Tokarev
Hello.
Just noticed that at least on ext4, unlinking a non-existing file from a read-only filesystem results in EROFS instead of ENOENT. I'd expect it return ENOENT - it is more logical, at least in my opinion.
Quoted 8 lines
Quoted 2 lines
For one, (readonly) NFS mount returns ENOENT in this case.
Um, it doesn't for me. Testing on v3.0-rc1:
# ls /test/foo; rm /test/foo ls: cannot access /test/foo: No such file or directory rm: cannot remove `/test/foo': No such file or directory
This is a hack in coreutils rm to work around this kernel change. The comment at
http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/remove.c#n450
says:
/* The unlinkat from kernels like linux-2.6.32 reports EROFS even for
nonexistent files. When the file is indeed missing, map that to ENOENT, so that rm -f ignores it, as required. Even without -f, this is useful because it makes rm print the more precise diagnostic. */
so that rm(1) calls stat(2) to see if the file actually exist if unlinkat() returned EROFS, and turns this errno into ENOENT.
That is, rm(1) output is not a good indicator. Use
strace rm -f /test/foo 2>&1 | grep unlink
to see the actual errno reported by the kernel.
Here's the POSIX description of unlink (and unlinkat) again:
http://pubs.opengroup.org/onlinepubs/009695399/functions/unlink.html
Thanks!
/mjt
Quoted 26 lines · Michael Tokarev
Thank you for the answer. I thought noone will reply... ;)
Quoted 9 lines · Ted Ts'o
Quoted 8 lines · Michael Tokarev
Hello.
Just noticed that at least on ext4, unlinking a non-existing file from a read-only filesystem results in EROFS instead of ENOENT. I'd expect it return ENOENT - it is more logical, at least in my opinion.
Quoted 8 lines
Quoted 2 lines
For one, (readonly) NFS mount returns ENOENT in this case.
Um, it doesn't for me. Testing on v3.0-rc1:
# ls /test/foo; rm /test/foo ls: cannot access /test/foo: No such file or directory rm: cannot remove `/test/foo': No such file or directoryThis is a hack in coreutils rm to work around this kernel change. The comment at
http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/remove.c#n450
says:
Quoted 8 lines
/* The unlinkat from kernels like linux-2.6.32 reports EROFS even for
nonexistent files. When the file is indeed missing, map that to ENOENT, so that rm -f ignores it, as required. Even without -f, this is useful because it makes rm print the more precise diagnostic. */so that rm(1) calls stat(2) to see if the file actually exist if
unlinkat()returned EROFS, and turns this errno into ENOENT.
And another followup to this, -- the original case when I actually
noticed the problem. A readonly-mounted root filesystem with /etc
in git (the repository is in /var, symlinked from /etc/.git). I deleted a few files from /etc (when it was readwrite), and noticed that I forgot to commit the change. So I used `git rm oldfiles' and voila, git, for the first time, refused to commit stuff for me in this configuration, -- before, I was always able to _commit_ the changes even if the working tree is read-only. It works for everything but not for unlinks.
Quoted 17 lines
That is, rm(1) output is not a good indicator. Use
strace rm -f /test/foo 2>&1 | grep unlink
to see the actual errno reported by the kernel.
Here's the POSIX description of unlink (and unlinkat) again:
http://pubs.opengroup.org/onlinepubs/009695399/functions/unlink.htmlThanks!
/mjt
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Quoted 8 lines · Michael Tokarev
Thank you for the answer. I thought noone will reply... ;)
Quoted 5 lines
Quoted 5 lines
Just noticed that at least on ext4, unlinking a non-existing file from a read-only filesystem results in EROFS instead of ENOENT. I'd expect it return ENOENT - it is more logical, at least in my opinion.
Quoted 4 lines
/* The unlinkat from kernels like linux-2.6.32 reports EROFS even for
nonexistent files. When the file is indeed missing, map that to ENOENT, so that rm -f ignores it, as required. Even without -f, this is useful because it makes rm print the more precise diagnostic. */
OK, I see what's going on. This check is in the VFS layer, so it affects all filesystems; it's not an ext4-specific thing.
Patch coming shortly.
- Ted
PATCH 1/1 vfs: make unlink() return ENOENT in preference to EROFS
If user space attempts to unlink a non-existent file, and the file system is mounted read-only, return ENOENT instead of EROFS. Either error code is arguably valid/correct, but ENOENT is a more specific error message.
--- fs/namei.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
fs/namei.c +2 -2
@@ -2708,9 +2708,9 @@ static long do_unlinkat(int dfd, const char __user *pathname) error =PTR_ERR (dentry);if (!IS_ERR (dentry)) {/* Why not before? Because we want correct error value */ -if (nd.last.name[nd.last.len]) - goto slashes; inode = dentry->d_inode; +if (nd.last.name[nd.last.len] || !inode) + goto slashes;if (inode)ihold (inode); error =mnt_want_write (nd.path.mnt);
Signature · 1 line
1.7.4.1.22.gec8e1.dirty