Skip to content

Commit

Permalink
NFS: nfs_rename() handle -ERESTARTSYS dentry left behind
Browse files Browse the repository at this point in the history
An interrupted rename will leave the old dentry behind if the rename
succeeds.  Fix this by moving the final local work of the rename to
rpc_call_done so that the results of the RENAME can always be handled,
even if the original process has already returned with -ERESTARTSYS.

Signed-off-by: Benjamin Coddington <[email protected]>
Signed-off-by: Anna Schumaker <[email protected]>
  • Loading branch information
Benjamin Coddington authored and amschuma-ntap committed Feb 8, 2017
1 parent 68e33bd commit 920b453
Showing 1 changed file with 25 additions and 11 deletions.
36 changes: 25 additions & 11 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -2002,6 +2002,29 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
}
EXPORT_SYMBOL_GPL(nfs_link);

static void
nfs_complete_rename(struct rpc_task *task, struct nfs_renamedata *data)
{
struct dentry *old_dentry = data->old_dentry;
struct dentry *new_dentry = data->new_dentry;
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);

nfs_mark_for_revalidate(old_inode);

switch (task->tk_status) {
case 0:
if (new_inode != NULL)
nfs_drop_nlink(new_inode);
d_move(old_dentry, new_dentry);
nfs_set_verifier(new_dentry,
nfs_save_change_attribute(data->new_dir));
break;
case -ENOENT:
nfs_dentry_handle_enoent(old_dentry);
}
}

/*
* RENAME
* FIXME: Some nfsds, like the Linux user space nfsd, may generate a
Expand Down Expand Up @@ -2084,7 +2107,8 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_inode != NULL)
NFS_PROTO(new_inode)->return_delegation(new_inode);

task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
nfs_complete_rename);
if (IS_ERR(task)) {
error = PTR_ERR(task);
goto out;
Expand All @@ -2094,21 +2118,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (error == 0)
error = task->tk_status;
rpc_put_task(task);
nfs_mark_for_revalidate(old_inode);
out:
if (rehash)
d_rehash(rehash);
trace_nfs_rename_exit(old_dir, old_dentry,
new_dir, new_dentry, error);
if (!error) {
if (new_inode != NULL)
nfs_drop_nlink(new_inode);
d_move(old_dentry, new_dentry);
nfs_set_verifier(new_dentry,
nfs_save_change_attribute(new_dir));
} else if (error == -ENOENT)
nfs_dentry_handle_enoent(old_dentry);

/* new dentry created? */
if (dentry)
dput(dentry);
Expand Down

0 comments on commit 920b453

Please sign in to comment.