aboutsummaryrefslogtreecommitdiff
path: root/fs/ext4
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2014-04-01 17:08:43 +0200
committerAlex Shi <alex.shi@linaro.org>2015-04-17 15:39:11 +0800
commitf1bdf915fa37836cc39f76e86c65521504deb7e1 (patch)
tree67f028356253ad7cdfe703216f8d47389031921c /fs/ext4
parent148622f8708456dda3262bbbe08742a962a0d667 (diff)
vfs: add RENAME_NOREPLACE flag
If this flag is specified and the target of the rename exists then the rename syscall fails with EEXIST. The VFS does the existence checking, so it is trivial to enable for most local filesystems. This patch only enables it in ext4. For network filesystems the VFS check is not enough as there may be a race between a remote create and the rename, so these filesystems need to handle this flag in their ->rename() implementations to ensure atomicity. Andy writes about why this is useful: "The trivial answer: to eliminate the race condition from 'mv -i'. Another answer: there's a common pattern to atomically create a file with contents: open a temporary file, write to it, optionally fsync it, close it, then link(2) it to the final name, then unlink the temporary file. The reason to use link(2) is because it won't silently clobber the destination. This is annoying: - It requires an extra system call that shouldn't be necessary. - It doesn't work on (IMO sensible) filesystems that don't support hard links (e.g. vfat). - It's not atomic -- there's an intermediate state where both files exist. - It's ugly. The new rename flag will make this totally sensible. To be fair, on new enough kernels, you can also use O_TMPFILE and linkat to achieve the same thing even more cleanly." Suggested-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Reviewed-by: J. Bruce Fields <bfields@redhat.com> (cherry picked from commit 0a7c3937a1f23f8cb5fc77ae01661e9968a51d0c) Signed-off-by: Alex Shi <alex.shi@linaro.org>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/namei.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2dcbfb6245d8..f0598d6e5722 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3191,6 +3191,16 @@ end_rename:
return retval;
}
+static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
+{
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
+ return ext4_rename(old_dir, old_dentry, new_dir, new_dentry);
+}
+
/*
* directories can handle most operations...
*/
@@ -3205,6 +3215,7 @@ const struct inode_operations ext4_dir_inode_operations = {
.mknod = ext4_mknod,
.tmpfile = ext4_tmpfile,
.rename = ext4_rename,
+ .rename2 = ext4_rename2,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,