Commit 520c8b16505236fc82daa352e6c5e73cd9870cff
1 parent
bc27027a73
Exists in
master
and in
13 other branches
vfs: add renameat2 syscall
Add new renameat2 syscall, which is the same as renameat with an added flags argument. Pass flags to vfs_rename() and to i_op->rename() as well. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Reviewed-by: J. Bruce Fields <bfields@redhat.com>
Showing 10 changed files with 58 additions and 15 deletions Side-by-side Diff
Documentation/filesystems/Locking
... | ... | @@ -47,6 +47,8 @@ |
47 | 47 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); |
48 | 48 | int (*rename) (struct inode *, struct dentry *, |
49 | 49 | struct inode *, struct dentry *); |
50 | + int (*rename2) (struct inode *, struct dentry *, | |
51 | + struct inode *, struct dentry *, unsigned int); | |
50 | 52 | int (*readlink) (struct dentry *, char __user *,int); |
51 | 53 | void * (*follow_link) (struct dentry *, struct nameidata *); |
52 | 54 | void (*put_link) (struct dentry *, struct nameidata *, void *); |
... | ... | @@ -78,6 +80,7 @@ |
78 | 80 | unlink: yes (both) |
79 | 81 | rmdir: yes (both) (see below) |
80 | 82 | rename: yes (all) (see below) |
83 | +rename2: yes (all) (see below) | |
81 | 84 | readlink: no |
82 | 85 | follow_link: no |
83 | 86 | put_link: no |
... | ... | @@ -96,7 +99,8 @@ |
96 | 99 | |
97 | 100 | Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on |
98 | 101 | victim. |
99 | - cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. | |
102 | + cross-directory ->rename() and rename2() has (per-superblock) | |
103 | +->s_vfs_rename_sem. | |
100 | 104 | |
101 | 105 | See Documentation/filesystems/directory-locking for more detailed discussion |
102 | 106 | of the locking scheme for directory operations. |
Documentation/filesystems/vfs.txt
... | ... | @@ -347,6 +347,8 @@ |
347 | 347 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); |
348 | 348 | int (*rename) (struct inode *, struct dentry *, |
349 | 349 | struct inode *, struct dentry *); |
350 | + int (*rename2) (struct inode *, struct dentry *, | |
351 | + struct inode *, struct dentry *, unsigned int); | |
350 | 352 | int (*readlink) (struct dentry *, char __user *,int); |
351 | 353 | void * (*follow_link) (struct dentry *, struct nameidata *); |
352 | 354 | void (*put_link) (struct dentry *, struct nameidata *, void *); |
... | ... | @@ -413,6 +415,20 @@ |
413 | 415 | |
414 | 416 | rename: called by the rename(2) system call to rename the object to |
415 | 417 | have the parent and name given by the second inode and dentry. |
418 | + | |
419 | + rename2: this has an additional flags argument compared to rename. | |
420 | + If no flags are supported by the filesystem then this method | |
421 | + need not be implemented. If some flags are supported then the | |
422 | + filesystem must return -EINVAL for any unsupported or unknown | |
423 | + flags. Currently the following flags are implemented: | |
424 | + (1) RENAME_NOREPLACE: this flag indicates that if the target | |
425 | + of the rename exists the rename should fail with -EEXIST | |
426 | + instead of replacing the target. The VFS already checks for | |
427 | + existence, so for local filesystems the RENAME_NOREPLACE | |
428 | + implementation is equivalent to plain rename. | |
429 | + (2) RENAME_EXCHANGE: exchange source and target. Both must | |
430 | + exist; this is checked by the VFS. Unlike plain rename, | |
431 | + source and target may be of different type. | |
416 | 432 | |
417 | 433 | readlink: called by the readlink(2) system call. Only required if |
418 | 434 | you want to support reading symbolic links |
arch/x86/syscalls/syscall_64.tbl
... | ... | @@ -322,6 +322,7 @@ |
322 | 322 | 313 common finit_module sys_finit_module |
323 | 323 | 314 common sched_setattr sys_sched_setattr |
324 | 324 | 315 common sched_getattr sys_sched_getattr |
325 | +316 common renameat2 sys_renameat2 | |
325 | 326 | |
326 | 327 | # |
327 | 328 | # x32-specific system call numbers start at 512 to avoid cache impact |
drivers/staging/lustre/lustre/include/linux/lustre_compat25.h
... | ... | @@ -105,8 +105,8 @@ |
105 | 105 | #define ll_vfs_unlink(inode,entry,mnt) vfs_unlink(inode,entry) |
106 | 106 | #define ll_vfs_mknod(dir,entry,mnt,mode,dev) vfs_mknod(dir,entry,mode,dev) |
107 | 107 | #define ll_security_inode_unlink(dir,entry,mnt) security_inode_unlink(dir,entry) |
108 | -#define ll_vfs_rename(old,old_dir,mnt,new,new_dir,mnt1,delegated_inode) \ | |
109 | - vfs_rename(old,old_dir,new,new_dir,delegated_inode) | |
108 | +#define ll_vfs_rename(old, old_dir, mnt, new, new_dir, mnt1) \ | |
109 | + vfs_rename(old, old_dir, new, new_dir, NULL, 0) | |
110 | 110 | |
111 | 111 | #define cfs_bio_io_error(a,b) bio_io_error((a)) |
112 | 112 | #define cfs_bio_endio(a,b,c) bio_endio((a),(c)) |
drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
fs/cachefiles/namei.c
... | ... | @@ -396,7 +396,7 @@ |
396 | 396 | cachefiles_io_error(cache, "Rename security error %d", ret); |
397 | 397 | } else { |
398 | 398 | ret = vfs_rename(dir->d_inode, rep, |
399 | - cache->graveyard->d_inode, grave, NULL); | |
399 | + cache->graveyard->d_inode, grave, NULL, 0); | |
400 | 400 | if (ret != 0 && ret != -ENOMEM) |
401 | 401 | cachefiles_io_error(cache, |
402 | 402 | "Rename failed with error %d", ret); |
fs/ecryptfs/inode.c
fs/namei.c
... | ... | @@ -3980,6 +3980,7 @@ |
3980 | 3980 | * @new_dir: parent of destination |
3981 | 3981 | * @new_dentry: destination |
3982 | 3982 | * @delegated_inode: returns an inode needing a delegation break |
3983 | + * @flags: rename flags | |
3983 | 3984 | * |
3984 | 3985 | * The caller must hold multiple mutexes--see lock_rename()). |
3985 | 3986 | * |
... | ... | @@ -4023,7 +4024,7 @@ |
4023 | 4024 | */ |
4024 | 4025 | int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
4025 | 4026 | struct inode *new_dir, struct dentry *new_dentry, |
4026 | - struct inode **delegated_inode) | |
4027 | + struct inode **delegated_inode, unsigned int flags) | |
4027 | 4028 | { |
4028 | 4029 | int error; |
4029 | 4030 | bool is_dir = d_is_dir(old_dentry); |
... | ... | @@ -4048,6 +4049,9 @@ |
4048 | 4049 | if (!old_dir->i_op->rename) |
4049 | 4050 | return -EPERM; |
4050 | 4051 | |
4052 | + if (flags && !old_dir->i_op->rename2) | |
4053 | + return -EINVAL; | |
4054 | + | |
4051 | 4055 | /* |
4052 | 4056 | * If we are going to change the parent - check write permissions, |
4053 | 4057 | * we'll need to flip '..'. |
... | ... | @@ -4093,7 +4097,13 @@ |
4093 | 4097 | goto out; |
4094 | 4098 | } |
4095 | 4099 | } |
4096 | - error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); | |
4100 | + if (!flags) { | |
4101 | + error = old_dir->i_op->rename(old_dir, old_dentry, | |
4102 | + new_dir, new_dentry); | |
4103 | + } else { | |
4104 | + error = old_dir->i_op->rename2(old_dir, old_dentry, | |
4105 | + new_dir, new_dentry, flags); | |
4106 | + } | |
4097 | 4107 | if (error) |
4098 | 4108 | goto out; |
4099 | 4109 | |
... | ... | @@ -4118,8 +4128,8 @@ |
4118 | 4128 | return error; |
4119 | 4129 | } |
4120 | 4130 | |
4121 | -SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, | |
4122 | - int, newdfd, const char __user *, newname) | |
4131 | +SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname, | |
4132 | + int, newdfd, const char __user *, newname, unsigned int, flags) | |
4123 | 4133 | { |
4124 | 4134 | struct dentry *old_dir, *new_dir; |
4125 | 4135 | struct dentry *old_dentry, *new_dentry; |
... | ... | @@ -4131,6 +4141,10 @@ |
4131 | 4141 | unsigned int lookup_flags = 0; |
4132 | 4142 | bool should_retry = false; |
4133 | 4143 | int error; |
4144 | + | |
4145 | + if (flags) | |
4146 | + return -EINVAL; | |
4147 | + | |
4134 | 4148 | retry: |
4135 | 4149 | from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags); |
4136 | 4150 | if (IS_ERR(from)) { |
... | ... | @@ -4202,8 +4216,8 @@ |
4202 | 4216 | if (error) |
4203 | 4217 | goto exit5; |
4204 | 4218 | error = vfs_rename(old_dir->d_inode, old_dentry, |
4205 | - new_dir->d_inode, new_dentry, | |
4206 | - &delegated_inode); | |
4219 | + new_dir->d_inode, new_dentry, | |
4220 | + &delegated_inode, flags); | |
4207 | 4221 | exit5: |
4208 | 4222 | dput(new_dentry); |
4209 | 4223 | exit4: |
4210 | 4224 | |
... | ... | @@ -4233,9 +4247,15 @@ |
4233 | 4247 | return error; |
4234 | 4248 | } |
4235 | 4249 | |
4250 | +SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, | |
4251 | + int, newdfd, const char __user *, newname) | |
4252 | +{ | |
4253 | + return sys_renameat2(olddfd, oldname, newdfd, newname, 0); | |
4254 | +} | |
4255 | + | |
4236 | 4256 | SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname) |
4237 | 4257 | { |
4238 | - return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname); | |
4258 | + return sys_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0); | |
4239 | 4259 | } |
4240 | 4260 | |
4241 | 4261 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) |
fs/nfsd/vfs.c
... | ... | @@ -1694,7 +1694,7 @@ |
1694 | 1694 | if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry) |
1695 | 1695 | goto out_dput_new; |
1696 | 1696 | |
1697 | - host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL); | |
1697 | + host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0); | |
1698 | 1698 | if (!host_err) { |
1699 | 1699 | host_err = commit_metadata(tfhp); |
1700 | 1700 | if (!host_err) |
include/linux/fs.h
... | ... | @@ -1460,7 +1460,7 @@ |
1460 | 1460 | extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **); |
1461 | 1461 | extern int vfs_rmdir(struct inode *, struct dentry *); |
1462 | 1462 | extern int vfs_unlink(struct inode *, struct dentry *, struct inode **); |
1463 | -extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **); | |
1463 | +extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int); | |
1464 | 1464 | |
1465 | 1465 | /* |
1466 | 1466 | * VFS dentry helper functions. |
... | ... | @@ -1571,6 +1571,8 @@ |
1571 | 1571 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); |
1572 | 1572 | int (*rename) (struct inode *, struct dentry *, |
1573 | 1573 | struct inode *, struct dentry *); |
1574 | + int (*rename2) (struct inode *, struct dentry *, | |
1575 | + struct inode *, struct dentry *, unsigned int); | |
1574 | 1576 | int (*setattr) (struct dentry *, struct iattr *); |
1575 | 1577 | int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); |
1576 | 1578 | int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); |