diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/sunrpc/clnt.c | 5 | ||||
| -rw-r--r-- | net/sunrpc/sched.c | 27 |
2 files changed, 23 insertions, 9 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 822f020fa7f4..1915ffe598e3 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -610,11 +610,6 @@ EXPORT_SYMBOL_GPL(rpc_killall_tasks); | |||
| 610 | */ | 610 | */ |
| 611 | void rpc_shutdown_client(struct rpc_clnt *clnt) | 611 | void rpc_shutdown_client(struct rpc_clnt *clnt) |
| 612 | { | 612 | { |
| 613 | /* | ||
| 614 | * To avoid deadlock, never call rpc_shutdown_client from a | ||
| 615 | * workqueue context! | ||
| 616 | */ | ||
| 617 | WARN_ON_ONCE(current->flags & PF_WQ_WORKER); | ||
| 618 | might_sleep(); | 613 | might_sleep(); |
| 619 | 614 | ||
| 620 | dprintk_rcu("RPC: shutting down %s client for %s\n", | 615 | dprintk_rcu("RPC: shutting down %s client for %s\n", |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index d17a704aaf5f..b4133bd13915 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -934,16 +934,35 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) | |||
| 934 | return task; | 934 | return task; |
| 935 | } | 935 | } |
| 936 | 936 | ||
| 937 | /* | ||
| 938 | * rpc_free_task - release rpc task and perform cleanups | ||
| 939 | * | ||
| 940 | * Note that we free up the rpc_task _after_ rpc_release_calldata() | ||
| 941 | * in order to work around a workqueue dependency issue. | ||
| 942 | * | ||
| 943 | * Tejun Heo states: | ||
| 944 | * "Workqueue currently considers two work items to be the same if they're | ||
| 945 | * on the same address and won't execute them concurrently - ie. it | ||
| 946 | * makes a work item which is queued again while being executed wait | ||
| 947 | * for the previous execution to complete. | ||
| 948 | * | ||
| 949 | * If a work function frees the work item, and then waits for an event | ||
| 950 | * which should be performed by another work item and *that* work item | ||
| 951 | * recycles the freed work item, it can create a false dependency loop. | ||
| 952 | * There really is no reliable way to detect this short of verifying | ||
| 953 | * every memory free." | ||
| 954 | * | ||
| 955 | */ | ||
| 937 | static void rpc_free_task(struct rpc_task *task) | 956 | static void rpc_free_task(struct rpc_task *task) |
| 938 | { | 957 | { |
| 939 | const struct rpc_call_ops *tk_ops = task->tk_ops; | 958 | unsigned short tk_flags = task->tk_flags; |
| 940 | void *calldata = task->tk_calldata; | 959 | |
| 960 | rpc_release_calldata(task->tk_ops, task->tk_calldata); | ||
| 941 | 961 | ||
| 942 | if (task->tk_flags & RPC_TASK_DYNAMIC) { | 962 | if (tk_flags & RPC_TASK_DYNAMIC) { |
| 943 | dprintk("RPC: %5u freeing task\n", task->tk_pid); | 963 | dprintk("RPC: %5u freeing task\n", task->tk_pid); |
| 944 | mempool_free(task, rpc_task_mempool); | 964 | mempool_free(task, rpc_task_mempool); |
| 945 | } | 965 | } |
| 946 | rpc_release_calldata(tk_ops, calldata); | ||
| 947 | } | 966 | } |
| 948 | 967 | ||
| 949 | static void rpc_async_release(struct work_struct *work) | 968 | static void rpc_async_release(struct work_struct *work) |
