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

Commit 818a8dbe authored by Benjamin Coddington's avatar Benjamin Coddington Committed by Anna Schumaker
Browse files

NFS: nfs_rename() - revalidate directories on -ERESTARTSYS



An interrupted rename will leave the old dentry behind if the rename
succeeds.  Fix this by forcing a lookup the next time through
->d_revalidate.

A previous attempt at solving this problem took the approach to complete
the work of the rename asynchronously, however that approach was wrong
since it would allow the d_move() to occur after the directory's i_mutex
had been dropped by the original process.

Signed-off-by: default avatarBenjamin Coddington <bcodding@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent a7a3b1e9
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -2056,7 +2056,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
	}

	error = rpc_wait_for_completion_task(task);
	if (error == 0)
	if (error != 0) {
		((struct nfs_renamedata *)task->tk_calldata)->cancelled = 1;
		/* Paired with the atomic_dec_and_test() barrier in rpc_do_put_task() */
		smp_wmb();
	} else
		error = task->tk_status;
	rpc_put_task(task);
out:
+13 −0
Original line number Diff line number Diff line
@@ -288,6 +288,19 @@ static void nfs_async_rename_release(void *calldata)
	if (d_really_is_positive(data->old_dentry))
		nfs_mark_for_revalidate(d_inode(data->old_dentry));

	/* The result of the rename is unknown. Play it safe by
	 * forcing a new lookup */
	if (data->cancelled) {
		spin_lock(&data->old_dir->i_lock);
		nfs_force_lookup_revalidate(data->old_dir);
		spin_unlock(&data->old_dir->i_lock);
		if (data->new_dir != data->old_dir) {
			spin_lock(&data->new_dir->i_lock);
			nfs_force_lookup_revalidate(data->new_dir);
			spin_unlock(&data->new_dir->i_lock);
		}
	}

	dput(data->old_dentry);
	dput(data->new_dentry);
	iput(data->old_dir);
+1 −0
Original line number Diff line number Diff line
@@ -1533,6 +1533,7 @@ struct nfs_renamedata {
	struct nfs_fattr	new_fattr;
	void (*complete)(struct rpc_task *, struct nfs_renamedata *);
	long timeout;
	bool cancelled;
};

struct nfs_access_entry;