diff options
author | J. Bruce Fields <bfields@redhat.com> | 2011-09-20 16:59:58 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-11-09 00:16:43 -0500 |
commit | 8e6d782cab50884ba94324632700e6233a252f6a (patch) | |
tree | 671b0c90795d8ab9d230018069b397c15f941af3 | |
parent | 5a14696c1795d3843673b5cf1982d0e5357a5bbf (diff) |
locks: break delegations on rename
Cc: David Howells <dhowells@redhat.com>
Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-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. |