aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/delegation.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-01-24 18:14:34 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-01-30 02:06:12 -0500
commite6f810759505bc86c009854b82cc495ffd8eb020 (patch)
tree1590631fe3b222d49015dd53b421a5547e13e4dc /fs/nfs/delegation.c
parent99fadcd76465842c014c88b8c9c19b457e9debc0 (diff)
NFS: Add an asynchronous delegreturn operation for use in nfs_clear_inode
Otherwise, there is a potential deadlock if the last dput() from an NFSv4 close() or other asynchronous operation leads to nfs_clear_inode calling the synchronous delegreturn. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/delegation.c')
-rw-r--r--fs/nfs/delegation.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index b03dcd8403f1..2dead8d1dd55 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -174,11 +174,11 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
174 return status; 174 return status;
175} 175}
176 176
177static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation) 177static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
178{ 178{
179 int res = 0; 179 int res = 0;
180 180
181 res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); 181 res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync);
182 nfs_free_delegation(delegation); 182 nfs_free_delegation(delegation);
183 return res; 183 return res;
184} 184}
@@ -208,7 +208,7 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
208 up_read(&clp->cl_sem); 208 up_read(&clp->cl_sem);
209 nfs_msync_inode(inode); 209 nfs_msync_inode(inode);
210 210
211 return nfs_do_return_delegation(inode, delegation); 211 return nfs_do_return_delegation(inode, delegation, 1);
212} 212}
213 213
214static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) 214static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
@@ -228,6 +228,27 @@ nomatch:
228 return NULL; 228 return NULL;
229} 229}
230 230
231/*
232 * This function returns the delegation without reclaiming opens
233 * or protecting against delegation reclaims.
234 * It is therefore really only safe to be called from
235 * nfs4_clear_inode()
236 */
237void nfs_inode_return_delegation_noreclaim(struct inode *inode)
238{
239 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
240 struct nfs_inode *nfsi = NFS_I(inode);
241 struct nfs_delegation *delegation;
242
243 if (rcu_dereference(nfsi->delegation) != NULL) {
244 spin_lock(&clp->cl_lock);
245 delegation = nfs_detach_delegation_locked(nfsi, NULL);
246 spin_unlock(&clp->cl_lock);
247 if (delegation != NULL)
248 nfs_do_return_delegation(inode, delegation, 0);
249 }
250}
251
231int nfs_inode_return_delegation(struct inode *inode) 252int nfs_inode_return_delegation(struct inode *inode)
232{ 253{
233 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; 254 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
@@ -388,7 +409,7 @@ static int recall_thread(void *data)
388 nfs_msync_inode(inode); 409 nfs_msync_inode(inode);
389 410
390 if (delegation != NULL) 411 if (delegation != NULL)
391 nfs_do_return_delegation(inode, delegation); 412 nfs_do_return_delegation(inode, delegation, 1);
392 iput(inode); 413 iput(inode);
393 module_put_and_exit(0); 414 module_put_and_exit(0);
394} 415}