aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-02-19 20:04:20 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-02-26 00:40:33 -0500
commit383ba71938519959be8e0b598ec658f0c211ff45 (patch)
tree01eb0155676fe69d40f01dc137ea3be952d88997
parent4b5621f6b127bce9218998c187bd25bf7f9fc371 (diff)
NFS: Fix a deadlock with lazy umount
We can't allow rpc callback functions like task->tk_ops->rpc_call_prepare() and task->tk_ops->rpc_call_done() to call mntput() in any way, since that will cause a deadlock when the call to rpc_shutdown_client() attempts to wait on 'task' to complete. We can avoid the above deadlock by moving calls to mntput to task->tk_ops->rpc_release() callback, since at that time the task will be marked as completed, and so rpc_shutdown_client won't attempt to wait on it. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/direct.c5
-rw-r--r--fs/nfs/inode.c6
-rw-r--r--fs/nfs/read.c7
-rw-r--r--fs/nfs/write.c13
4 files changed, 23 insertions, 8 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 16844f98f50e..e0170407a885 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -323,7 +323,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq,
323 data->inode = inode; 323 data->inode = inode;
324 data->cred = msg.rpc_cred; 324 data->cred = msg.rpc_cred;
325 data->args.fh = NFS_FH(inode); 325 data->args.fh = NFS_FH(inode);
326 data->args.context = ctx; 326 data->args.context = get_nfs_open_context(ctx);
327 data->args.offset = pos; 327 data->args.offset = pos;
328 data->args.pgbase = pgbase; 328 data->args.pgbase = pgbase;
329 data->args.pages = data->pagevec; 329 data->args.pages = data->pagevec;
@@ -546,6 +546,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
546 data->args.fh = NFS_FH(data->inode); 546 data->args.fh = NFS_FH(data->inode);
547 data->args.offset = 0; 547 data->args.offset = 0;
548 data->args.count = 0; 548 data->args.count = 0;
549 data->args.context = get_nfs_open_context(dreq->ctx);
549 data->res.count = 0; 550 data->res.count = 0;
550 data->res.fattr = &data->fattr; 551 data->res.fattr = &data->fattr;
551 data->res.verf = &data->verf; 552 data->res.verf = &data->verf;
@@ -728,7 +729,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq,
728 data->inode = inode; 729 data->inode = inode;
729 data->cred = msg.rpc_cred; 730 data->cred = msg.rpc_cred;
730 data->args.fh = NFS_FH(inode); 731 data->args.fh = NFS_FH(inode);
731 data->args.context = ctx; 732 data->args.context = get_nfs_open_context(ctx);
732 data->args.offset = pos; 733 data->args.offset = pos;
733 data->args.pgbase = pgbase; 734 data->args.pgbase = pgbase;
734 data->args.pages = data->pagevec; 735 data->args.pages = data->pagevec;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 966a8850aa30..a499fb58d858 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -521,8 +521,12 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
521 521
522static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) 522static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
523{ 523{
524 struct inode *inode = ctx->path.dentry->d_inode; 524 struct inode *inode;
525 525
526 if (ctx == NULL)
527 return;
528
529 inode = ctx->path.dentry->d_inode;
526 if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) 530 if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
527 return; 531 return;
528 list_del(&ctx->list); 532 list_del(&ctx->list);
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 3d7d9631e125..fab0d3720a03 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -73,7 +73,10 @@ static void nfs_readdata_free(struct nfs_read_data *rdata)
73 73
74void nfs_readdata_release(void *data) 74void nfs_readdata_release(void *data)
75{ 75{
76 nfs_readdata_free(data); 76 struct nfs_read_data *rdata = data;
77
78 put_nfs_open_context(rdata->args.context);
79 nfs_readdata_free(rdata);
77} 80}
78 81
79static 82static
@@ -186,7 +189,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
186 data->args.pgbase = req->wb_pgbase + offset; 189 data->args.pgbase = req->wb_pgbase + offset;
187 data->args.pages = data->pagevec; 190 data->args.pages = data->pagevec;
188 data->args.count = count; 191 data->args.count = count;
189 data->args.context = req->wb_context; 192 data->args.context = get_nfs_open_context(req->wb_context);
190 193
191 data->res.fattr = &data->fattr; 194 data->res.fattr = &data->fattr;
192 data->res.count = count; 195 data->res.count = count;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 80c61fdb2720..69b4158d9a10 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -105,8 +105,11 @@ static void nfs_writedata_free(struct nfs_write_data *wdata)
105 call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); 105 call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free);
106} 106}
107 107
108void nfs_writedata_release(void *wdata) 108void nfs_writedata_release(void *data)
109{ 109{
110 struct nfs_write_data *wdata = data;
111
112 put_nfs_open_context(wdata->args.context);
110 nfs_writedata_free(wdata); 113 nfs_writedata_free(wdata);
111} 114}
112 115
@@ -816,7 +819,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
816 data->args.pgbase = req->wb_pgbase + offset; 819 data->args.pgbase = req->wb_pgbase + offset;
817 data->args.pages = data->pagevec; 820 data->args.pages = data->pagevec;
818 data->args.count = count; 821 data->args.count = count;
819 data->args.context = req->wb_context; 822 data->args.context = get_nfs_open_context(req->wb_context);
820 data->args.stable = NFS_UNSTABLE; 823 data->args.stable = NFS_UNSTABLE;
821 if (how & FLUSH_STABLE) { 824 if (how & FLUSH_STABLE) {
822 data->args.stable = NFS_DATA_SYNC; 825 data->args.stable = NFS_DATA_SYNC;
@@ -1153,8 +1156,11 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1153 1156
1154 1157
1155#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 1158#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
1156void nfs_commit_release(void *wdata) 1159void nfs_commit_release(void *data)
1157{ 1160{
1161 struct nfs_write_data *wdata = data;
1162
1163 put_nfs_open_context(wdata->args.context);
1158 nfs_commit_free(wdata); 1164 nfs_commit_free(wdata);
1159} 1165}
1160 1166
@@ -1197,6 +1203,7 @@ static void nfs_commit_rpcsetup(struct list_head *head,
1197 /* Note: we always request a commit of the entire inode */ 1203 /* Note: we always request a commit of the entire inode */
1198 data->args.offset = 0; 1204 data->args.offset = 0;
1199 data->args.count = 0; 1205 data->args.count = 0;
1206 data->args.context = get_nfs_open_context(first->wb_context);
1200 data->res.count = 0; 1207 data->res.count = 0;
1201 data->res.fattr = &data->fattr; 1208 data->res.fattr = &data->fattr;
1202 data->res.verf = &data->verf; 1209 data->res.verf = &data->verf;