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

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
...@@ -2056,7 +2056,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2056,7 +2056,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
error = rpc_wait_for_completion_task(task); 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; error = task->tk_status;
rpc_put_task(task); rpc_put_task(task);
out: out:
......
...@@ -288,6 +288,19 @@ static void nfs_async_rename_release(void *calldata) ...@@ -288,6 +288,19 @@ static void nfs_async_rename_release(void *calldata)
if (d_really_is_positive(data->old_dentry)) if (d_really_is_positive(data->old_dentry))
nfs_mark_for_revalidate(d_inode(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->old_dentry);
dput(data->new_dentry); dput(data->new_dentry);
iput(data->old_dir); iput(data->old_dir);
......
...@@ -1533,6 +1533,7 @@ struct nfs_renamedata { ...@@ -1533,6 +1533,7 @@ struct nfs_renamedata {
struct nfs_fattr new_fattr; struct nfs_fattr new_fattr;
void (*complete)(struct rpc_task *, struct nfs_renamedata *); void (*complete)(struct rpc_task *, struct nfs_renamedata *);
long timeout; long timeout;
bool cancelled;
}; };
struct nfs_access_entry; struct nfs_access_entry;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment