diff options
| -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 | 3 | ||||
| -rw-r--r-- | fs/namei.c | 47 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 2 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 |
7 files changed, 51 insertions, 11 deletions
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 9243dfab43d3..80b019bf969c 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) \ | 108 | #define ll_vfs_rename(old,old_dir,mnt,new,new_dir,mnt1,delegated_inode) \ |
| 109 | vfs_rename(old,old_dir,new,new_dir) | 109 | vfs_rename(old,old_dir,new,new_dir,delegated_inode) |
| 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 18e1b47a1d65..4ed7c9f0a8be 100644 --- a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c +++ b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c | |||
| @@ -220,7 +220,7 @@ int lustre_rename(struct dentry *dir, struct vfsmount *mnt, | |||
| 220 | GOTO(put_old, err = PTR_ERR(dchild_new)); | 220 | GOTO(put_old, err = PTR_ERR(dchild_new)); |
| 221 | 221 | ||
| 222 | err = ll_vfs_rename(dir->d_inode, dchild_old, mnt, | 222 | err = ll_vfs_rename(dir->d_inode, dchild_old, mnt, |
| 223 | dir->d_inode, dchild_new, mnt); | 223 | dir->d_inode, dchild_new, mnt, NULL); |
| 224 | 224 | ||
| 225 | dput(dchild_new); | 225 | dput(dchild_new); |
| 226 | put_old: | 226 | put_old: |
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 31d480c0e046..ca65f39dc8dc 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); | 399 | cache->graveyard->d_inode, grave, NULL); |
| 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 dc60b8bd09ec..c23b01bb7e04 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -640,7 +640,8 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 640 | goto out_lock; | 640 | goto out_lock; |
| 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 | if (rc) | 645 | if (rc) |
| 645 | goto out_lock; | 646 | goto out_lock; |
| 646 | if (target_inode) | 647 | if (target_inode) |
diff --git a/fs/namei.c b/fs/namei.c index cfaeaae0f2db..ce7e580e4e14 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -4022,7 +4022,8 @@ out: | |||
| 4022 | } | 4022 | } |
| 4023 | 4023 | ||
| 4024 | static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, | 4024 | static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, |
| 4025 | struct inode *new_dir, struct dentry *new_dentry) | 4025 | struct inode *new_dir, struct dentry *new_dentry, |
| 4026 | struct inode **delegated_inode) | ||
| 4026 | { | 4027 | { |
| 4027 | struct inode *target = new_dentry->d_inode; | 4028 | struct inode *target = new_dentry->d_inode; |
| 4028 | struct inode *source = old_dentry->d_inode; | 4029 | struct inode *source = old_dentry->d_inode; |
| @@ -4039,6 +4040,14 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, | |||
| 4039 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) | 4040 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) |
| 4040 | goto out; | 4041 | goto out; |
| 4041 | 4042 | ||
| 4043 | error = try_break_deleg(source, delegated_inode); | ||
| 4044 | if (error) | ||
| 4045 | goto out; | ||
| 4046 | if (target) { | ||
| 4047 | error = try_break_deleg(target, delegated_inode); | ||
| 4048 | if (error) | ||
| 4049 | goto out; | ||
| 4050 | } | ||
| 4042 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); | 4051 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); |
| 4043 | if (error) | 4052 | if (error) |
| 4044 | goto out; | 4053 | goto out; |
| @@ -4053,8 +4062,30 @@ out: | |||
| 4053 | return error; | 4062 | return error; |
| 4054 | } | 4063 | } |
| 4055 | 4064 | ||
| 4065 | /** | ||
| 4066 | * vfs_rename - rename a filesystem object | ||
| 4067 | * @old_dir: parent of source | ||
| 4068 | * @old_dentry: source | ||
| 4069 | * @new_dir: parent of destination | ||
| 4070 | * @new_dentry: destination | ||
| 4071 | * @delegated_inode: returns an inode needing a delegation break | ||
| 4072 | * | ||
| 4073 | * The caller must hold multiple mutexes--see lock_rename()). | ||
| 4074 | * | ||
| 4075 | * If vfs_rename discovers a delegation in need of breaking at either | ||
| 4076 | * the source or destination, it will return -EWOULDBLOCK and return a | ||
| 4077 | * reference to the inode in delegated_inode. The caller should then | ||
| 4078 | * break the delegation and retry. Because breaking a delegation may | ||
| 4079 | * take a long time, the caller should drop all locks before doing | ||
| 4080 | * so. | ||
| 4081 | * | ||
| 4082 | * Alternatively, a caller may pass NULL for delegated_inode. This may | ||
| 4083 | * be appropriate for callers that expect the underlying filesystem not | ||
| 4084 | * to be NFS exported. | ||
| 4085 | */ | ||
| 4056 | int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 4086 | int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
| 4057 | struct inode *new_dir, struct dentry *new_dentry) | 4087 | struct inode *new_dir, struct dentry *new_dentry, |
| 4088 | struct inode **delegated_inode) | ||
| 4058 | { | 4089 | { |
| 4059 | int error; | 4090 | int error; |
| 4060 | int is_dir = d_is_directory(old_dentry) || d_is_autodir(old_dentry); | 4091 | int is_dir = d_is_directory(old_dentry) || d_is_autodir(old_dentry); |
| @@ -4082,7 +4113,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 4082 | if (is_dir) | 4113 | if (is_dir) |
| 4083 | error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); | 4114 | error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); |
| 4084 | else | 4115 | else |
| 4085 | error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); | 4116 | error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry,delegated_inode); |
| 4086 | if (!error) | 4117 | if (!error) |
| 4087 | fsnotify_move(old_dir, new_dir, old_name, is_dir, | 4118 | fsnotify_move(old_dir, new_dir, old_name, is_dir, |
| 4088 | new_dentry->d_inode, old_dentry); | 4119 | new_dentry->d_inode, old_dentry); |
| @@ -4098,6 +4129,7 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, | |||
| 4098 | struct dentry *old_dentry, *new_dentry; | 4129 | struct dentry *old_dentry, *new_dentry; |
| 4099 | struct dentry *trap; | 4130 | struct dentry *trap; |
| 4100 | struct nameidata oldnd, newnd; | 4131 | struct nameidata oldnd, newnd; |
| 4132 | struct inode *delegated_inode = NULL; | ||
| 4101 | struct filename *from; | 4133 | struct filename *from; |
| 4102 | struct filename *to; | 4134 | struct filename *to; |
| 4103 | unsigned int lookup_flags = 0; | 4135 | unsigned int lookup_flags = 0; |
| @@ -4137,6 +4169,7 @@ retry: | |||
| 4137 | newnd.flags &= ~LOOKUP_PARENT; | 4169 | newnd.flags &= ~LOOKUP_PARENT; |
| 4138 | newnd.flags |= LOOKUP_RENAME_TARGET; | 4170 | newnd.flags |= LOOKUP_RENAME_TARGET; |
| 4139 | 4171 | ||
| 4172 | retry_deleg: | ||
| 4140 | trap = lock_rename(new_dir, old_dir); | 4173 | trap = lock_rename(new_dir, old_dir); |
| 4141 | 4174 | ||
| 4142 | old_dentry = lookup_hash(&oldnd); | 4175 | old_dentry = lookup_hash(&oldnd); |
| @@ -4173,13 +4206,19 @@ retry: | |||
| 4173 | if (error) | 4206 | if (error) |
| 4174 | goto exit5; | 4207 | goto exit5; |
| 4175 | error = vfs_rename(old_dir->d_inode, old_dentry, | 4208 | error = vfs_rename(old_dir->d_inode, old_dentry, |
| 4176 | new_dir->d_inode, new_dentry); | 4209 | new_dir->d_inode, new_dentry, |
| 4210 | &delegated_inode); | ||
| 4177 | exit5: | 4211 | exit5: |
| 4178 | dput(new_dentry); | 4212 | dput(new_dentry); |
| 4179 | exit4: | 4213 | exit4: |
| 4180 | dput(old_dentry); | 4214 | dput(old_dentry); |
| 4181 | exit3: | 4215 | exit3: |
| 4182 | unlock_rename(new_dir, old_dir); | 4216 | unlock_rename(new_dir, old_dir); |
| 4217 | if (delegated_inode) { | ||
| 4218 | error = break_deleg_wait(&delegated_inode); | ||
| 4219 | if (!error) | ||
| 4220 | goto retry_deleg; | ||
| 4221 | } | ||
| 4183 | mnt_drop_write(oldnd.path.mnt); | 4222 | mnt_drop_write(oldnd.path.mnt); |
| 4184 | exit2: | 4223 | exit2: |
| 4185 | if (retry_estale(error, lookup_flags)) | 4224 | if (retry_estale(error, lookup_flags)) |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7a810235d599..45bf0295894d 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -1837,7 +1837,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
| 1837 | if (host_err) | 1837 | if (host_err) |
| 1838 | goto out_dput_new; | 1838 | goto out_dput_new; |
| 1839 | } | 1839 | } |
| 1840 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1840 | host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL); |
| 1841 | if (!host_err) { | 1841 | if (!host_err) { |
| 1842 | host_err = commit_metadata(tfhp); | 1842 | host_err = commit_metadata(tfhp); |
| 1843 | if (!host_err) | 1843 | if (!host_err) |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 931f919f44e1..5bcff883fa90 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1456,7 +1456,7 @@ extern int vfs_symlink(struct inode *, struct dentry *, const char *); | |||
| 1456 | extern int vfs_link(struct dentry *, struct inode *, struct dentry *); | 1456 | extern int vfs_link(struct dentry *, struct inode *, struct dentry *); |
| 1457 | extern int vfs_rmdir(struct inode *, struct dentry *); | 1457 | extern int vfs_rmdir(struct inode *, struct dentry *); |
| 1458 | extern int vfs_unlink(struct inode *, struct dentry *, struct inode **); | 1458 | extern int vfs_unlink(struct inode *, struct dentry *, struct inode **); |
| 1459 | extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); | 1459 | extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **); |
| 1460 | 1460 | ||
| 1461 | /* | 1461 | /* |
| 1462 | * VFS dentry helper functions. | 1462 | * VFS dentry helper functions. |
