aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Coddington <bcodding@redhat.com>2017-02-01 00:00:07 -0500
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2017-02-08 17:02:44 -0500
commit920b4530fb80430ff30ef83efe21ba1fa5623731 (patch)
treee09a3508c339c4f6feeba20f14a7104e77370a03
parent68e33bd6bbb79819e5cb7bce26559191b144c465 (diff)
NFS: nfs_rename() handle -ERESTARTSYS dentry left behind
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 <bcodding@redhat.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r--fs/nfs/dir.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index fad81041f5ab..fb499a3f21b5 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2002,6 +2002,29 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
2002} 2002}
2003EXPORT_SYMBOL_GPL(nfs_link); 2003EXPORT_SYMBOL_GPL(nfs_link);
2004 2004
2005static void
2006nfs_complete_rename(struct rpc_task *task, struct nfs_renamedata *data)
2007{
2008 struct dentry *old_dentry = data->old_dentry;
2009 struct dentry *new_dentry = data->new_dentry;
2010 struct inode *old_inode = d_inode(old_dentry);
2011 struct inode *new_inode = d_inode(new_dentry);
2012
2013 nfs_mark_for_revalidate(old_inode);
2014
2015 switch (task->tk_status) {
2016 case 0:
2017 if (new_inode != NULL)
2018 nfs_drop_nlink(new_inode);
2019 d_move(old_dentry, new_dentry);
2020 nfs_set_verifier(new_dentry,
2021 nfs_save_change_attribute(data->new_dir));
2022 break;
2023 case -ENOENT:
2024 nfs_dentry_handle_enoent(old_dentry);
2025 }
2026}
2027
2005/* 2028/*
2006 * RENAME 2029 * RENAME
2007 * FIXME: Some nfsds, like the Linux user space nfsd, may generate a 2030 * FIXME: Some nfsds, like the Linux user space nfsd, may generate a
@@ -2084,7 +2107,8 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
2084 if (new_inode != NULL) 2107 if (new_inode != NULL)
2085 NFS_PROTO(new_inode)->return_delegation(new_inode); 2108 NFS_PROTO(new_inode)->return_delegation(new_inode);
2086 2109
2087 task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL); 2110 task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
2111 nfs_complete_rename);
2088 if (IS_ERR(task)) { 2112 if (IS_ERR(task)) {
2089 error = PTR_ERR(task); 2113 error = PTR_ERR(task);
2090 goto out; 2114 goto out;
@@ -2094,21 +2118,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
2094 if (error == 0) 2118 if (error == 0)
2095 error = task->tk_status; 2119 error = task->tk_status;
2096 rpc_put_task(task); 2120 rpc_put_task(task);
2097 nfs_mark_for_revalidate(old_inode);
2098out: 2121out:
2099 if (rehash) 2122 if (rehash)
2100 d_rehash(rehash); 2123 d_rehash(rehash);
2101 trace_nfs_rename_exit(old_dir, old_dentry, 2124 trace_nfs_rename_exit(old_dir, old_dentry,
2102 new_dir, new_dentry, error); 2125 new_dir, new_dentry, error);
2103 if (!error) {
2104 if (new_inode != NULL)
2105 nfs_drop_nlink(new_inode);
2106 d_move(old_dentry, new_dentry);
2107 nfs_set_verifier(new_dentry,
2108 nfs_save_change_attribute(new_dir));
2109 } else if (error == -ENOENT)
2110 nfs_dentry_handle_enoent(old_dentry);
2111
2112 /* new dentry created? */ 2126 /* new dentry created? */
2113 if (dentry) 2127 if (dentry)
2114 dput(dentry); 2128 dput(dentry);