Commit 477687e1 authored by Trond Myklebust's avatar Trond Myklebust

SUNRPC: Fix up RPC back channel transmission

Now that transmissions happen through a queue, we require the RPC tasks
to handle error conditions that may have been set while they were
sleeping. The back channel does not currently do this, but assumes
that any error condition happens during its own call to xprt_transmit().

The solution is to ensure that the back channel splits out the
error handling just like the forward channel does.

Fixes: 89f90fe1 ("SUNRPC: Allow calls to xprt_transmit() to drain...")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent ed7dc973
...@@ -66,9 +66,6 @@ static void call_decode(struct rpc_task *task); ...@@ -66,9 +66,6 @@ static void call_decode(struct rpc_task *task);
static void call_bind(struct rpc_task *task); static void call_bind(struct rpc_task *task);
static void call_bind_status(struct rpc_task *task); static void call_bind_status(struct rpc_task *task);
static void call_transmit(struct rpc_task *task); static void call_transmit(struct rpc_task *task);
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
static void call_bc_transmit(struct rpc_task *task);
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
static void call_status(struct rpc_task *task); static void call_status(struct rpc_task *task);
static void call_transmit_status(struct rpc_task *task); static void call_transmit_status(struct rpc_task *task);
static void call_refresh(struct rpc_task *task); static void call_refresh(struct rpc_task *task);
...@@ -1133,6 +1130,8 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags, ...@@ -1133,6 +1130,8 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,
EXPORT_SYMBOL_GPL(rpc_call_async); EXPORT_SYMBOL_GPL(rpc_call_async);
#if defined(CONFIG_SUNRPC_BACKCHANNEL) #if defined(CONFIG_SUNRPC_BACKCHANNEL)
static void call_bc_encode(struct rpc_task *task);
/** /**
* rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run
* rpc_execute against it * rpc_execute against it
...@@ -1154,7 +1153,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) ...@@ -1154,7 +1153,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req)
task = rpc_new_task(&task_setup_data); task = rpc_new_task(&task_setup_data);
xprt_init_bc_request(req, task); xprt_init_bc_request(req, task);
task->tk_action = call_bc_transmit; task->tk_action = call_bc_encode;
atomic_inc(&task->tk_count); atomic_inc(&task->tk_count);
WARN_ON_ONCE(atomic_read(&task->tk_count) != 2); WARN_ON_ONCE(atomic_read(&task->tk_count) != 2);
rpc_execute(task); rpc_execute(task);
...@@ -2085,6 +2084,16 @@ call_transmit_status(struct rpc_task *task) ...@@ -2085,6 +2084,16 @@ call_transmit_status(struct rpc_task *task)
} }
#if defined(CONFIG_SUNRPC_BACKCHANNEL) #if defined(CONFIG_SUNRPC_BACKCHANNEL)
static void call_bc_transmit(struct rpc_task *task);
static void call_bc_transmit_status(struct rpc_task *task);
static void
call_bc_encode(struct rpc_task *task)
{
xprt_request_enqueue_transmit(task);
task->tk_action = call_bc_transmit;
}
/* /*
* 5b. Send the backchannel RPC reply. On error, drop the reply. In * 5b. Send the backchannel RPC reply. On error, drop the reply. In
* addition, disconnect on connectivity errors. * addition, disconnect on connectivity errors.
...@@ -2092,26 +2101,23 @@ call_transmit_status(struct rpc_task *task) ...@@ -2092,26 +2101,23 @@ call_transmit_status(struct rpc_task *task)
static void static void
call_bc_transmit(struct rpc_task *task) call_bc_transmit(struct rpc_task *task)
{ {
struct rpc_rqst *req = task->tk_rqstp; task->tk_action = call_bc_transmit_status;
if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) {
if (rpc_task_need_encode(task)) if (!xprt_prepare_transmit(task))
xprt_request_enqueue_transmit(task); return;
if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) task->tk_status = 0;
goto out_wakeup; xprt_transmit(task);
if (!xprt_prepare_transmit(task))
goto out_retry;
if (task->tk_status < 0) {
printk(KERN_NOTICE "RPC: Could not send backchannel reply "
"error: %d\n", task->tk_status);
goto out_done;
} }
xprt_end_transmit(task);
}
xprt_transmit(task); static void
call_bc_transmit_status(struct rpc_task *task)
{
struct rpc_rqst *req = task->tk_rqstp;
xprt_end_transmit(task);
dprint_status(task); dprint_status(task);
switch (task->tk_status) { switch (task->tk_status) {
case 0: case 0:
/* Success */ /* Success */
...@@ -2125,8 +2131,14 @@ call_bc_transmit(struct rpc_task *task) ...@@ -2125,8 +2131,14 @@ call_bc_transmit(struct rpc_task *task)
case -ENOTCONN: case -ENOTCONN:
case -EPIPE: case -EPIPE:
break; break;
case -ENOBUFS:
rpc_delay(task, HZ>>2);
/* fall through */
case -EBADSLT:
case -EAGAIN: case -EAGAIN:
goto out_retry; task->tk_status = 0;
task->tk_action = call_bc_transmit;
return;
case -ETIMEDOUT: case -ETIMEDOUT:
/* /*
* Problem reaching the server. Disconnect and let the * Problem reaching the server. Disconnect and let the
...@@ -2145,18 +2157,11 @@ call_bc_transmit(struct rpc_task *task) ...@@ -2145,18 +2157,11 @@ call_bc_transmit(struct rpc_task *task)
* We were unable to reply and will have to drop the * We were unable to reply and will have to drop the
* request. The server should reconnect and retransmit. * request. The server should reconnect and retransmit.
*/ */
WARN_ON_ONCE(task->tk_status == -EAGAIN);
printk(KERN_NOTICE "RPC: Could not send backchannel reply " printk(KERN_NOTICE "RPC: Could not send backchannel reply "
"error: %d\n", task->tk_status); "error: %d\n", task->tk_status);
break; break;
} }
out_wakeup:
rpc_wake_up_queued_task(&req->rq_xprt->pending, task);
out_done:
task->tk_action = rpc_exit_task; task->tk_action = rpc_exit_task;
return;
out_retry:
task->tk_status = 0;
} }
#endif /* CONFIG_SUNRPC_BACKCHANNEL */ #endif /* CONFIG_SUNRPC_BACKCHANNEL */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment