diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2014-04-01 11:08:42 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-04-01 11:08:42 -0400 |
commit | 520c8b16505236fc82daa352e6c5e73cd9870cff (patch) | |
tree | e61b78440874e083928821423e226c0ecc2d6647 | |
parent | bc27027a73e8b80376b51a1583ad1c7445605e8a (diff) |
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>
-rw-r--r-- | Documentation/filesystems/Locking | 6 | ||||
-rw-r--r-- | Documentation/filesystems/vfs.txt | 16 | ||||
-rw-r--r-- | arch/x86/syscalls/syscall_64.tbl | 1 | ||||
-rw-r--r-- | drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 4 | ||||
-rw-r--r-- | drivers/staging/lustre/lustre/lvfs/lvfs_linux.c | 2 | ||||
-rw-r--r-- | fs/cachefiles/namei.c | 2 | ||||
-rw-r--r-- | fs/ecryptfs/inode.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 34 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 4 |
10 files changed, 58 insertions, 15 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 5b0c083d7c0e..f424e0e5b46b 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
@@ -47,6 +47,8 @@ prototypes: | |||
47 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); | 47 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); |
48 | int (*rename) (struct inode *, struct dentry *, | 48 | int (*rename) (struct inode *, struct dentry *, |
49 | struct inode *, struct dentry *); | 49 | struct inode *, struct dentry *); |
50 | int (*rename2) (struct inode *, struct dentry *, | ||
51 | struct inode *, struct dentry *, unsigned int); | ||
50 | int (*readlink) (struct dentry *, char __user *,int); | 52 | int (*readlink) (struct dentry *, char __user *,int); |
51 | void * (*follow_link) (struct dentry *, struct nameidata *); | 53 | void * (*follow_link) (struct dentry *, struct nameidata *); |
52 | void (*put_link) (struct dentry *, struct nameidata *, void *); | 54 | void (*put_link) (struct dentry *, struct nameidata *, void *); |
@@ -78,6 +80,7 @@ mkdir: yes | |||
78 | unlink: yes (both) | 80 | unlink: yes (both) |
79 | rmdir: yes (both) (see below) | 81 | rmdir: yes (both) (see below) |
80 | rename: yes (all) (see below) | 82 | rename: yes (all) (see below) |
83 | rename2: yes (all) (see below) | ||
81 | readlink: no | 84 | readlink: no |
82 | follow_link: no | 85 | follow_link: no |
83 | put_link: no | 86 | put_link: no |
@@ -96,7 +99,8 @@ tmpfile: no | |||
96 | 99 | ||
97 | Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on | 100 | Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on |
98 | victim. | 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 | See Documentation/filesystems/directory-locking for more detailed discussion | 105 | See Documentation/filesystems/directory-locking for more detailed discussion |
102 | of the locking scheme for directory operations. | 106 | of the locking scheme for directory operations. |
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index c53784c119c8..94eb86287bcb 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
@@ -347,6 +347,8 @@ struct inode_operations { | |||
347 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); | 347 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); |
348 | int (*rename) (struct inode *, struct dentry *, | 348 | int (*rename) (struct inode *, struct dentry *, |
349 | struct inode *, struct dentry *); | 349 | struct inode *, struct dentry *); |
350 | int (*rename2) (struct inode *, struct dentry *, | ||
351 | struct inode *, struct dentry *, unsigned int); | ||
350 | int (*readlink) (struct dentry *, char __user *,int); | 352 | int (*readlink) (struct dentry *, char __user *,int); |
351 | void * (*follow_link) (struct dentry *, struct nameidata *); | 353 | void * (*follow_link) (struct dentry *, struct nameidata *); |
352 | void (*put_link) (struct dentry *, struct nameidata *, void *); | 354 | void (*put_link) (struct dentry *, struct nameidata *, void *); |
@@ -414,6 +416,20 @@ otherwise noted. | |||
414 | rename: called by the rename(2) system call to rename the object to | 416 | rename: called by the rename(2) system call to rename the object to |
415 | have the parent and name given by the second inode and dentry. | 417 | have the parent and name given by the second inode and dentry. |
416 | 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. | ||
432 | |||
417 | readlink: called by the readlink(2) system call. Only required if | 433 | readlink: called by the readlink(2) system call. Only required if |
418 | you want to support reading symbolic links | 434 | you want to support reading symbolic links |
419 | 435 | ||
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index a12bddc7ccea..04376ac3d9ef 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl | |||
@@ -322,6 +322,7 @@ | |||
322 | 313 common finit_module sys_finit_module | 322 | 313 common finit_module sys_finit_module |
323 | 314 common sched_setattr sys_sched_setattr | 323 | 314 common sched_setattr sys_sched_setattr |
324 | 315 common sched_getattr sys_sched_getattr | 324 | 315 common sched_getattr sys_sched_getattr |
325 | 316 common renameat2 sys_renameat2 | ||
325 | 326 | ||
326 | # | 327 | # |
327 | # x32-specific system call numbers start at 512 to avoid cache impact | 328 | # x32-specific system call numbers start at 512 to avoid cache impact |
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index eefdb8d061b1..81cc7a0134bb 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | |||
@@ -105,8 +105,8 @@ static inline void ll_set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt, | |||
105 | #define ll_vfs_unlink(inode,entry,mnt) vfs_unlink(inode,entry) | 105 | #define ll_vfs_unlink(inode,entry,mnt) vfs_unlink(inode,entry) |
106 | #define ll_vfs_mknod(dir,entry,mnt,mode,dev) vfs_mknod(dir,entry,mode,dev) | 106 | #define ll_vfs_mknod(dir,entry,mnt,mode,dev) vfs_mknod(dir,entry,mode,dev) |
107 | #define ll_security_inode_unlink(dir,entry,mnt) security_inode_unlink(dir,entry) | 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) \ | 108 | #define ll_vfs_rename(old, old_dir, mnt, new, new_dir, mnt1) \ |
109 | vfs_rename(old,old_dir,new,new_dir,delegated_inode) | 109 | vfs_rename(old, old_dir, new, new_dir, NULL, 0) |
110 | 110 | ||
111 | #define cfs_bio_io_error(a,b) bio_io_error((a)) | 111 | #define cfs_bio_io_error(a,b) bio_io_error((a)) |
112 | #define cfs_bio_endio(a,b,c) bio_endio((a),(c)) | 112 | #define cfs_bio_endio(a,b,c) bio_endio((a),(c)) |
diff --git a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c index 428ffd8c37b7..d50822be3230 100644 --- a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c +++ b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c | |||
@@ -223,7 +223,7 @@ int lustre_rename(struct dentry *dir, struct vfsmount *mnt, | |||
223 | GOTO(put_old, err = PTR_ERR(dchild_new)); | 223 | GOTO(put_old, err = PTR_ERR(dchild_new)); |
224 | 224 | ||
225 | err = ll_vfs_rename(dir->d_inode, dchild_old, mnt, | 225 | err = ll_vfs_rename(dir->d_inode, dchild_old, mnt, |
226 | dir->d_inode, dchild_new, mnt, NULL); | 226 | dir->d_inode, dchild_new, mnt); |
227 | 227 | ||
228 | dput(dchild_new); | 228 | dput(dchild_new); |
229 | put_old: | 229 | put_old: |
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index ca65f39dc8dc..31088a969351 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -396,7 +396,7 @@ try_again: | |||
396 | cachefiles_io_error(cache, "Rename security error %d", ret); | 396 | cachefiles_io_error(cache, "Rename security error %d", ret); |
397 | } else { | 397 | } else { |
398 | ret = vfs_rename(dir->d_inode, rep, | 398 | ret = vfs_rename(dir->d_inode, rep, |
399 | cache->graveyard->d_inode, grave, NULL); | 399 | cache->graveyard->d_inode, grave, NULL, 0); |
400 | if (ret != 0 && ret != -ENOMEM) | 400 | if (ret != 0 && ret != -ENOMEM) |
401 | cachefiles_io_error(cache, | 401 | cachefiles_io_error(cache, |
402 | "Rename failed with error %d", ret); | 402 | "Rename failed with error %d", ret); |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index b167ca48b8ee..d4a9431ec73c 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
@@ -641,7 +641,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
641 | } | 641 | } |
642 | rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, | 642 | rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, |
643 | lower_new_dir_dentry->d_inode, lower_new_dentry, | 643 | lower_new_dir_dentry->d_inode, lower_new_dentry, |
644 | NULL); | 644 | NULL, 0); |
645 | if (rc) | 645 | if (rc) |
646 | goto out_lock; | 646 | goto out_lock; |
647 | if (target_inode) | 647 | if (target_inode) |
diff --git a/fs/namei.c b/fs/namei.c index 12b8f56ba942..ab4e48c4a80a 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -3980,6 +3980,7 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname | |||
3980 | * @new_dir: parent of destination | 3980 | * @new_dir: parent of destination |
3981 | * @new_dentry: destination | 3981 | * @new_dentry: destination |
3982 | * @delegated_inode: returns an inode needing a delegation break | 3982 | * @delegated_inode: returns an inode needing a delegation break |
3983 | * @flags: rename flags | ||
3983 | * | 3984 | * |
3984 | * The caller must hold multiple mutexes--see lock_rename()). | 3985 | * The caller must hold multiple mutexes--see lock_rename()). |
3985 | * | 3986 | * |
@@ -4023,7 +4024,7 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname | |||
4023 | */ | 4024 | */ |
4024 | int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 4025 | int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
4025 | struct inode *new_dir, struct dentry *new_dentry, | 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 | int error; | 4029 | int error; |
4029 | bool is_dir = d_is_dir(old_dentry); | 4030 | bool is_dir = d_is_dir(old_dentry); |
@@ -4048,6 +4049,9 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
4048 | if (!old_dir->i_op->rename) | 4049 | if (!old_dir->i_op->rename) |
4049 | return -EPERM; | 4050 | return -EPERM; |
4050 | 4051 | ||
4052 | if (flags && !old_dir->i_op->rename2) | ||
4053 | return -EINVAL; | ||
4054 | |||
4051 | /* | 4055 | /* |
4052 | * If we are going to change the parent - check write permissions, | 4056 | * If we are going to change the parent - check write permissions, |
4053 | * we'll need to flip '..'. | 4057 | * we'll need to flip '..'. |
@@ -4093,7 +4097,13 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
4093 | goto out; | 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 | if (error) | 4107 | if (error) |
4098 | goto out; | 4108 | goto out; |
4099 | 4109 | ||
@@ -4118,8 +4128,8 @@ out: | |||
4118 | return error; | 4128 | return error; |
4119 | } | 4129 | } |
4120 | 4130 | ||
4121 | SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, | 4131 | SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname, |
4122 | int, newdfd, const char __user *, newname) | 4132 | int, newdfd, const char __user *, newname, unsigned int, flags) |
4123 | { | 4133 | { |
4124 | struct dentry *old_dir, *new_dir; | 4134 | struct dentry *old_dir, *new_dir; |
4125 | struct dentry *old_dentry, *new_dentry; | 4135 | struct dentry *old_dentry, *new_dentry; |
@@ -4131,6 +4141,10 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, | |||
4131 | unsigned int lookup_flags = 0; | 4141 | unsigned int lookup_flags = 0; |
4132 | bool should_retry = false; | 4142 | bool should_retry = false; |
4133 | int error; | 4143 | int error; |
4144 | |||
4145 | if (flags) | ||
4146 | return -EINVAL; | ||
4147 | |||
4134 | retry: | 4148 | retry: |
4135 | from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags); | 4149 | from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags); |
4136 | if (IS_ERR(from)) { | 4150 | if (IS_ERR(from)) { |
@@ -4202,8 +4216,8 @@ retry_deleg: | |||
4202 | if (error) | 4216 | if (error) |
4203 | goto exit5; | 4217 | goto exit5; |
4204 | error = vfs_rename(old_dir->d_inode, old_dentry, | 4218 | error = vfs_rename(old_dir->d_inode, old_dentry, |
4205 | new_dir->d_inode, new_dentry, | 4219 | new_dir->d_inode, new_dentry, |
4206 | &delegated_inode); | 4220 | &delegated_inode, flags); |
4207 | exit5: | 4221 | exit5: |
4208 | dput(new_dentry); | 4222 | dput(new_dentry); |
4209 | exit4: | 4223 | exit4: |
@@ -4233,9 +4247,15 @@ exit: | |||
4233 | return error; | 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 | SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname) | 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 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) | 4261 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 6d7be3f80356..915808b36df7 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1694,7 +1694,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1694 | if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry) | 1694 | if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry) |
1695 | goto out_dput_new; | 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 | if (!host_err) { | 1698 | if (!host_err) { |
1699 | host_err = commit_metadata(tfhp); | 1699 | host_err = commit_metadata(tfhp); |
1700 | if (!host_err) | 1700 | if (!host_err) |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 23b2a35d712e..3b3670e97da6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1460,7 +1460,7 @@ extern int vfs_symlink(struct inode *, struct dentry *, const char *); | |||
1460 | extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **); | 1460 | extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **); |
1461 | extern int vfs_rmdir(struct inode *, struct dentry *); | 1461 | extern int vfs_rmdir(struct inode *, struct dentry *); |
1462 | extern int vfs_unlink(struct inode *, struct dentry *, struct inode **); | 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 | * VFS dentry helper functions. | 1466 | * VFS dentry helper functions. |
@@ -1571,6 +1571,8 @@ struct inode_operations { | |||
1571 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); | 1571 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); |
1572 | int (*rename) (struct inode *, struct dentry *, | 1572 | int (*rename) (struct inode *, struct dentry *, |
1573 | struct inode *, struct dentry *); | 1573 | struct inode *, struct dentry *); |
1574 | int (*rename2) (struct inode *, struct dentry *, | ||
1575 | struct inode *, struct dentry *, unsigned int); | ||
1574 | int (*setattr) (struct dentry *, struct iattr *); | 1576 | int (*setattr) (struct dentry *, struct iattr *); |
1575 | int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); | 1577 | int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); |
1576 | int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); | 1578 | int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); |