On Thu, 2013-01-03 at 18:11 -0500, Trond Myklebust wrote: +AD4- On Thu, 2013-01-03 at 17:26 -0500, Tejun Heo wrote: +AD4- +AD4- Ooh, BTW, there was a bug where workqueue code created a false +AD4- +AD4- dependency between two work items. Workqueue currently considers two +AD4- +AD4- work items to be the same if they're on the same address and won't +AD4- +AD4- execute them concurrently - ie. it makes a work item which is queued +AD4- +AD4- again while being executed wait for the previous execution to +AD4- +AD4- complete. +AD4- +AD4- +AD4- +AD4- If a work function frees the work item, and then waits for an event +AD4- +AD4- which should be performed by another work item and +ACo-that+ACo- work item +AD4- +AD4- recycles the freed work item, it can create a false dependency loop. +AD4- +AD4- There really is no reliable way to detect this short of verifying +AD4- +AD4- every memory free. A patch is queued to make such occurrences less +AD4- +AD4- likely (work functions should also match for two work items considered +AD4- +AD4- the same), but if you're seeing this, the best thing to do is freeing +AD4- +AD4- the work item at the end of the work function. +AD4- +AD4- That's interesting... I wonder if we may have been hitting that issue. +AD4- +AD4- From what I can see, we do actually free the write RPC task (and hence +AD4- the work+AF8-struct) before we call the asynchronous unlink completion... +AD4- +AD4- Dros, can you see if reverting commit +AD4- 324d003b0cd82151adbaecefef57b73f7959a469 +- commit +AD4- 168e4b39d1afb79a7e3ea6c3bb246b4c82c6bdb9 and then applying the attached +AD4- patch also fixes the hang on a pristine 3.7.x kernel? Actually, we probably also need to look at rpc+AF8-free+AF8-task, so the following patch, instead... -- Trond Myklebust Linux NFS client maintainer NetApp Trond.Myklebust+AEA-netapp.com www.netapp.com
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index b6bdb18..400f7ec 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -91,12 +91,13 @@ void nfs_readdata_release(struct nfs_read_data *rdata) 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); + kfree(rdata); } EXPORT_SYMBOL_GPL(nfs_readdata_release); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index b673be3..45d9250 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -126,12 +126,13 @@ void nfs_writedata_release(struct nfs_write_data *wdata) 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); + kfree(wdata); } EXPORT_SYMBOL_GPL(nfs_writedata_release); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index d17a704..500407a 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -936,14 +936,13 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) static void rpc_free_task(struct rpc_task *task) { - const struct rpc_call_ops *tk_ops = task->tk_ops; - void *calldata = task->tk_calldata; + unsigned short tk_flags = task->tk_flags; - if (task->tk_flags & RPC_TASK_DYNAMIC) { + rpc_release_calldata(task->tk_ops, task->tk_calldata); + if (tk_flags & RPC_TASK_DYNAMIC) { dprintk("RPC: %5u freeing task\n", task->tk_pid); mempool_free(task, rpc_task_mempool); } - rpc_release_calldata(tk_ops, calldata); } static void rpc_async_release(struct work_struct *work)