aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-01-04 12:47:04 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-01-04 12:59:10 -0500
commit6db6dd7d3fd8f7c765dabc376493d6791ab28bd6 (patch)
tree3328dca5352ad54f3d12d484ee5742a9a5b67542 /fs/nfs
parentc6567ed1402c55e19b012e66a8398baec2a726f3 (diff)
NFS: Ensure that we free the rpc_task after read and write cleanups are done
This patch ensures that we free the rpc_task after the cleanup callbacks are done in order to avoid a deadlock problem that can be triggered if the callback needs to wait for another workqueue item to complete. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: Weston Andros Adamson <dros@netapp.com> Cc: Tejun Heo <tj@kernel.org> Cc: Bruce Fields <bfields@fieldses.org> Cc: stable@vger.kernel.org [>= 3.5]
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/read.c10
-rw-r--r--fs/nfs/write.c10
2 files changed, 14 insertions, 6 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index b6bdb18e892c..a5e5d9899d56 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -91,12 +91,16 @@ void nfs_readdata_release(struct nfs_read_data *rdata)
91 put_nfs_open_context(rdata->args.context); 91 put_nfs_open_context(rdata->args.context);
92 if (rdata->pages.pagevec != rdata->pages.page_array) 92 if (rdata->pages.pagevec != rdata->pages.page_array)
93 kfree(rdata->pages.pagevec); 93 kfree(rdata->pages.pagevec);
94 if (rdata != &read_header->rpc_data) 94 if (rdata == &read_header->rpc_data) {
95 kfree(rdata);
96 else
97 rdata->header = NULL; 95 rdata->header = NULL;
96 rdata = NULL;
97 }
98 if (atomic_dec_and_test(&hdr->refcnt)) 98 if (atomic_dec_and_test(&hdr->refcnt))
99 hdr->completion_ops->completion(hdr); 99 hdr->completion_ops->completion(hdr);
100 /* Note: we only free the rpc_task after callbacks are done.
101 * See the comment in rpc_free_task() for why
102 */
103 kfree(rdata);
100} 104}
101EXPORT_SYMBOL_GPL(nfs_readdata_release); 105EXPORT_SYMBOL_GPL(nfs_readdata_release);
102 106
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index b673be31590e..c483cc50b82e 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -126,12 +126,16 @@ void nfs_writedata_release(struct nfs_write_data *wdata)
126 put_nfs_open_context(wdata->args.context); 126 put_nfs_open_context(wdata->args.context);
127 if (wdata->pages.pagevec != wdata->pages.page_array) 127 if (wdata->pages.pagevec != wdata->pages.page_array)
128 kfree(wdata->pages.pagevec); 128 kfree(wdata->pages.pagevec);
129 if (wdata != &write_header->rpc_data) 129 if (wdata == &write_header->rpc_data) {
130 kfree(wdata);
131 else
132 wdata->header = NULL; 130 wdata->header = NULL;
131 wdata = NULL;
132 }
133 if (atomic_dec_and_test(&hdr->refcnt)) 133 if (atomic_dec_and_test(&hdr->refcnt))
134 hdr->completion_ops->completion(hdr); 134 hdr->completion_ops->completion(hdr);
135 /* Note: we only free the rpc_task after callbacks are done.
136 * See the comment in rpc_free_task() for why
137 */
138 kfree(wdata);
135} 139}
136EXPORT_SYMBOL_GPL(nfs_writedata_release); 140EXPORT_SYMBOL_GPL(nfs_writedata_release);
137 141