Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e6d782c authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Al Viro
Browse files

locks: break delegations on rename



Cc: David Howells <dhowells@redhat.com>
Acked-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 5a14696c
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -105,8 +105,8 @@ static inline void ll_set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt,
#define ll_vfs_unlink(inode,entry,mnt)	  vfs_unlink(inode,entry)
#define ll_vfs_mknod(dir,entry,mnt,mode,dev)    vfs_mknod(dir,entry,mode,dev)
#define ll_security_inode_unlink(dir,entry,mnt) security_inode_unlink(dir,entry)
#define ll_vfs_rename(old,old_dir,mnt,new,new_dir,mnt1) \
		vfs_rename(old,old_dir,new,new_dir)
#define ll_vfs_rename(old,old_dir,mnt,new,new_dir,mnt1,delegated_inode) \
		vfs_rename(old,old_dir,new,new_dir,delegated_inode)

#define cfs_bio_io_error(a,b)   bio_io_error((a))
#define cfs_bio_endio(a,b,c)    bio_endio((a),(c))
+1 −1
Original line number Diff line number Diff line
@@ -220,7 +220,7 @@ int lustre_rename(struct dentry *dir, struct vfsmount *mnt,
		GOTO(put_old, err = PTR_ERR(dchild_new));

	err = ll_vfs_rename(dir->d_inode, dchild_old, mnt,
			    dir->d_inode, dchild_new, mnt);
			    dir->d_inode, dchild_new, mnt, NULL);

	dput(dchild_new);
put_old:
+1 −1
Original line number Diff line number Diff line
@@ -396,7 +396,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
		cachefiles_io_error(cache, "Rename security error %d", ret);
	} else {
		ret = vfs_rename(dir->d_inode, rep,
				 cache->graveyard->d_inode, grave);
				 cache->graveyard->d_inode, grave, NULL);
		if (ret != 0 && ret != -ENOMEM)
			cachefiles_io_error(cache,
					    "Rename failed with error %d", ret);
+2 −1
Original line number Diff line number Diff line
@@ -640,7 +640,8 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		goto out_lock;
	}
	rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
			lower_new_dir_dentry->d_inode, lower_new_dentry);
			lower_new_dir_dentry->d_inode, lower_new_dentry,
			NULL);
	if (rc)
		goto out_lock;
	if (target_inode)
+43 −4
Original line number Diff line number Diff line
@@ -4022,7 +4022,8 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
}

static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
			    struct inode *new_dir, struct dentry *new_dentry)
			    struct inode *new_dir, struct dentry *new_dentry,
			    struct inode **delegated_inode)
{
	struct inode *target = new_dentry->d_inode;
	struct inode *source = old_dentry->d_inode;
@@ -4039,6 +4040,14 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
	if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
		goto out;

	error = try_break_deleg(source, delegated_inode);
	if (error)
		goto out;
	if (target) {
		error = try_break_deleg(target, delegated_inode);
		if (error)
			goto out;
	}
	error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
	if (error)
		goto out;
@@ -4053,8 +4062,30 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
	return error;
}

/**
 * vfs_rename - rename a filesystem object
 * @old_dir:	parent of source
 * @old_dentry:	source
 * @new_dir:	parent of destination
 * @new_dentry:	destination
 * @delegated_inode: returns an inode needing a delegation break
 *
 * The caller must hold multiple mutexes--see lock_rename()).
 *
 * If vfs_rename discovers a delegation in need of breaking at either
 * the source or destination, it will return -EWOULDBLOCK and return a
 * reference to the inode in delegated_inode.  The caller should then
 * break the delegation and retry.  Because breaking a delegation may
 * take a long time, the caller should drop all locks before doing
 * so.
 *
 * Alternatively, a caller may pass NULL for delegated_inode.  This may
 * be appropriate for callers that expect the underlying filesystem not
 * to be NFS exported.
 */
int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
	       struct inode *new_dir, struct dentry *new_dentry)
	       struct inode *new_dir, struct dentry *new_dentry,
	       struct inode **delegated_inode)
{
	int error;
	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,
	if (is_dir)
		error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
	else
		error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
		error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry,delegated_inode);
	if (!error)
		fsnotify_move(old_dir, new_dir, old_name, is_dir,
			      new_dentry->d_inode, old_dentry);
@@ -4098,6 +4129,7 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
	struct dentry *old_dentry, *new_dentry;
	struct dentry *trap;
	struct nameidata oldnd, newnd;
	struct inode *delegated_inode = NULL;
	struct filename *from;
	struct filename *to;
	unsigned int lookup_flags = 0;
@@ -4137,6 +4169,7 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
	newnd.flags &= ~LOOKUP_PARENT;
	newnd.flags |= LOOKUP_RENAME_TARGET;

retry_deleg:
	trap = lock_rename(new_dir, old_dir);

	old_dentry = lookup_hash(&oldnd);
@@ -4173,13 +4206,19 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
	if (error)
		goto exit5;
	error = vfs_rename(old_dir->d_inode, old_dentry,
				   new_dir->d_inode, new_dentry);
				   new_dir->d_inode, new_dentry,
				   &delegated_inode);
exit5:
	dput(new_dentry);
exit4:
	dput(old_dentry);
exit3:
	unlock_rename(new_dir, old_dir);
	if (delegated_inode) {
		error = break_deleg_wait(&delegated_inode);
		if (!error)
			goto retry_deleg;
	}
	mnt_drop_write(oldnd.path.mnt);
exit2:
	if (retry_estale(error, lookup_flags))
Loading