aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.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/nfs4proc.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/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 89efbcd6fd53..5c189bd57eb2 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2991,7 +2991,7 @@ static const struct rpc_call_ops nfs4_delegreturn_ops = {
2991 .rpc_release = nfs4_delegreturn_release, 2991 .rpc_release = nfs4_delegreturn_release,
2992}; 2992};
2993 2993
2994static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) 2994static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync)
2995{ 2995{
2996 struct nfs4_delegreturndata *data; 2996 struct nfs4_delegreturndata *data;
2997 struct nfs_server *server = NFS_SERVER(inode); 2997 struct nfs_server *server = NFS_SERVER(inode);
@@ -3006,7 +3006,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
3006 .callback_ops = &nfs4_delegreturn_ops, 3006 .callback_ops = &nfs4_delegreturn_ops,
3007 .flags = RPC_TASK_ASYNC, 3007 .flags = RPC_TASK_ASYNC,
3008 }; 3008 };
3009 int status; 3009 int status = 0;
3010 3010
3011 data = kmalloc(sizeof(*data), GFP_KERNEL); 3011 data = kmalloc(sizeof(*data), GFP_KERNEL);
3012 if (data == NULL) 3012 if (data == NULL)
@@ -3028,23 +3028,27 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
3028 task = rpc_run_task(&task_setup_data); 3028 task = rpc_run_task(&task_setup_data);
3029 if (IS_ERR(task)) 3029 if (IS_ERR(task))
3030 return PTR_ERR(task); 3030 return PTR_ERR(task);
3031 if (!issync)
3032 goto out;
3031 status = nfs4_wait_for_completion_rpc_task(task); 3033 status = nfs4_wait_for_completion_rpc_task(task);
3032 if (status == 0) { 3034 if (status != 0)
3033 status = data->rpc_status; 3035 goto out;
3034 if (status == 0) 3036 status = data->rpc_status;
3035 nfs_refresh_inode(inode, &data->fattr); 3037 if (status != 0)
3036 } 3038 goto out;
3039 nfs_refresh_inode(inode, &data->fattr);
3040out:
3037 rpc_put_task(task); 3041 rpc_put_task(task);
3038 return status; 3042 return status;
3039} 3043}
3040 3044
3041int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) 3045int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync)
3042{ 3046{
3043 struct nfs_server *server = NFS_SERVER(inode); 3047 struct nfs_server *server = NFS_SERVER(inode);
3044 struct nfs4_exception exception = { }; 3048 struct nfs4_exception exception = { };
3045 int err; 3049 int err;
3046 do { 3050 do {
3047 err = _nfs4_proc_delegreturn(inode, cred, stateid); 3051 err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
3048 switch (err) { 3052 switch (err) {
3049 case -NFS4ERR_STALE_STATEID: 3053 case -NFS4ERR_STALE_STATEID:
3050 case -NFS4ERR_EXPIRED: 3054 case -NFS4ERR_EXPIRED: