| From 6db6dd7d3fd8f7c765dabc376493d6791ab28bd6 Mon Sep 17 00:00:00 2001 |
| From: Trond Myklebust <Trond.Myklebust@netapp.com> |
| Date: Fri, 4 Jan 2013 12:47:04 -0500 |
| Subject: NFS: Ensure that we free the rpc_task after read and write cleanups are done |
| |
| From: Trond Myklebust <Trond.Myklebust@netapp.com> |
| |
| commit 6db6dd7d3fd8f7c765dabc376493d6791ab28bd6 upstream. |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/nfs/read.c | 10 +++++++--- |
| fs/nfs/write.c | 10 +++++++--- |
| 2 files changed, 14 insertions(+), 6 deletions(-) |
| |
| --- a/fs/nfs/read.c |
| +++ b/fs/nfs/read.c |
| @@ -91,12 +91,16 @@ void nfs_readdata_release(struct nfs_rea |
| put_nfs_open_context(rdata->args.context); |
| if (rdata->pages.pagevec != rdata->pages.page_array) |
| kfree(rdata->pages.pagevec); |
| - if (rdata != &read_header->rpc_data) |
| - kfree(rdata); |
| - else |
| + if (rdata == &read_header->rpc_data) { |
| rdata->header = NULL; |
| + rdata = NULL; |
| + } |
| if (atomic_dec_and_test(&hdr->refcnt)) |
| hdr->completion_ops->completion(hdr); |
| + /* Note: we only free the rpc_task after callbacks are done. |
| + * See the comment in rpc_free_task() for why |
| + */ |
| + kfree(rdata); |
| } |
| EXPORT_SYMBOL_GPL(nfs_readdata_release); |
| |
| --- a/fs/nfs/write.c |
| +++ b/fs/nfs/write.c |
| @@ -126,12 +126,16 @@ void nfs_writedata_release(struct nfs_wr |
| put_nfs_open_context(wdata->args.context); |
| if (wdata->pages.pagevec != wdata->pages.page_array) |
| kfree(wdata->pages.pagevec); |
| - if (wdata != &write_header->rpc_data) |
| - kfree(wdata); |
| - else |
| + if (wdata == &write_header->rpc_data) { |
| wdata->header = NULL; |
| + wdata = NULL; |
| + } |
| if (atomic_dec_and_test(&hdr->refcnt)) |
| hdr->completion_ops->completion(hdr); |
| + /* Note: we only free the rpc_task after callbacks are done. |
| + * See the comment in rpc_free_task() for why |
| + */ |
| + kfree(wdata); |
| } |
| EXPORT_SYMBOL_GPL(nfs_writedata_release); |
| |