aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-09-20 16:59:58 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-11-09 00:16:43 -0500
commit8e6d782cab50884ba94324632700e6233a252f6a (patch)
tree671b0c90795d8ab9d230018069b397c15f941af3
parent5a14696c1795d3843673b5cf1982d0e5357a5bbf (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.h4
-rw-r--r--drivers/staging/lustre/lustre/lvfs/lvfs_linux.c2
-rw-r--r--fs/cachefiles/namei.c2
-rw-r--r--fs/ecryptfs/inode.c3
-rw-r--r--fs/namei.c47
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--include/linux/fs.h2
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);
226put_old: 226put_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
4024static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, 4024static 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 */
4056int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, 4086int 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
4172retry_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);
4177exit5: 4211exit5:
4178 dput(new_dentry); 4212 dput(new_dentry);
4179exit4: 4213exit4:
4180 dput(old_dentry); 4214 dput(old_dentry);
4181exit3: 4215exit3:
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);
4184exit2: 4223exit2:
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 *);
1456extern int vfs_link(struct dentry *, struct inode *, struct dentry *); 1456extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
1457extern int vfs_rmdir(struct inode *, struct dentry *); 1457extern int vfs_rmdir(struct inode *, struct dentry *);
1458extern int vfs_unlink(struct inode *, struct dentry *, struct inode **); 1458extern int vfs_unlink(struct inode *, struct dentry *, struct inode **);
1459extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); 1459extern 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.