diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-02-19 20:04:20 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-02-26 00:40:33 -0500 |
commit | 383ba71938519959be8e0b598ec658f0c211ff45 (patch) | |
tree | 01eb0155676fe69d40f01dc137ea3be952d88997 /fs/nfs/write.c | |
parent | 4b5621f6b127bce9218998c187bd25bf7f9fc371 (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>
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 13 |
1 files changed, 10 insertions, 3 deletions
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 | ||
108 | void nfs_writedata_release(void *wdata) | 108 | void 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) |
1156 | void nfs_commit_release(void *wdata) | 1159 | void 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; |