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: Benjamin Coddington <bcodding@redhat.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
a7a3b1e971
commit
818a8dbe83
|
@ -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)
|
||||||
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 {
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue