|
@@ -169,6 +169,17 @@ out:
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(xprt_load_transport);
|
|
EXPORT_SYMBOL_GPL(xprt_load_transport);
|
|
|
|
|
|
|
|
+static void xprt_clear_locked(struct rpc_xprt *xprt)
|
|
|
|
+{
|
|
|
|
+ xprt->snd_task = NULL;
|
|
|
|
+ if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) {
|
|
|
|
+ smp_mb__before_atomic();
|
|
|
|
+ clear_bit(XPRT_LOCKED, &xprt->state);
|
|
|
|
+ smp_mb__after_atomic();
|
|
|
|
+ } else
|
|
|
|
+ queue_work(xprtiod_workqueue, &xprt->task_cleanup);
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* xprt_reserve_xprt - serialize write access to transports
|
|
* xprt_reserve_xprt - serialize write access to transports
|
|
* @task: task that is requesting access to the transport
|
|
* @task: task that is requesting access to the transport
|
|
@@ -188,10 +199,14 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
|
|
return 1;
|
|
return 1;
|
|
goto out_sleep;
|
|
goto out_sleep;
|
|
}
|
|
}
|
|
|
|
+ if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
|
|
|
|
+ goto out_unlock;
|
|
xprt->snd_task = task;
|
|
xprt->snd_task = task;
|
|
|
|
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
|
|
+out_unlock:
|
|
|
|
+ xprt_clear_locked(xprt);
|
|
out_sleep:
|
|
out_sleep:
|
|
dprintk("RPC: %5u failed to lock transport %p\n",
|
|
dprintk("RPC: %5u failed to lock transport %p\n",
|
|
task->tk_pid, xprt);
|
|
task->tk_pid, xprt);
|
|
@@ -208,17 +223,6 @@ out_sleep:
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
|
|
EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
|
|
|
|
|
|
-static void xprt_clear_locked(struct rpc_xprt *xprt)
|
|
|
|
-{
|
|
|
|
- xprt->snd_task = NULL;
|
|
|
|
- if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) {
|
|
|
|
- smp_mb__before_atomic();
|
|
|
|
- clear_bit(XPRT_LOCKED, &xprt->state);
|
|
|
|
- smp_mb__after_atomic();
|
|
|
|
- } else
|
|
|
|
- queue_work(xprtiod_workqueue, &xprt->task_cleanup);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static bool
|
|
static bool
|
|
xprt_need_congestion_window_wait(struct rpc_xprt *xprt)
|
|
xprt_need_congestion_window_wait(struct rpc_xprt *xprt)
|
|
{
|
|
{
|
|
@@ -267,10 +271,13 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
|
|
xprt->snd_task = task;
|
|
xprt->snd_task = task;
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
+ if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
|
|
|
|
+ goto out_unlock;
|
|
if (!xprt_need_congestion_window_wait(xprt)) {
|
|
if (!xprt_need_congestion_window_wait(xprt)) {
|
|
xprt->snd_task = task;
|
|
xprt->snd_task = task;
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
+out_unlock:
|
|
xprt_clear_locked(xprt);
|
|
xprt_clear_locked(xprt);
|
|
out_sleep:
|
|
out_sleep:
|
|
dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt);
|
|
dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt);
|
|
@@ -309,10 +316,12 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt)
|
|
{
|
|
{
|
|
if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
|
|
if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
|
|
return;
|
|
return;
|
|
-
|
|
|
|
|
|
+ if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
|
|
|
|
+ goto out_unlock;
|
|
if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending,
|
|
if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending,
|
|
__xprt_lock_write_func, xprt))
|
|
__xprt_lock_write_func, xprt))
|
|
return;
|
|
return;
|
|
|
|
+out_unlock:
|
|
xprt_clear_locked(xprt);
|
|
xprt_clear_locked(xprt);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -320,6 +329,8 @@ static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
|
|
{
|
|
{
|
|
if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
|
|
if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
|
|
return;
|
|
return;
|
|
|
|
+ if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
|
|
|
|
+ goto out_unlock;
|
|
if (xprt_need_congestion_window_wait(xprt))
|
|
if (xprt_need_congestion_window_wait(xprt))
|
|
goto out_unlock;
|
|
goto out_unlock;
|
|
if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending,
|
|
if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending,
|
|
@@ -510,39 +521,46 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
|
|
|
|
|
|
/**
|
|
/**
|
|
* xprt_wait_for_buffer_space - wait for transport output buffer to clear
|
|
* xprt_wait_for_buffer_space - wait for transport output buffer to clear
|
|
- * @task: task to be put to sleep
|
|
|
|
- * @action: function pointer to be executed after wait
|
|
|
|
|
|
+ * @xprt: transport
|
|
*
|
|
*
|
|
* Note that we only set the timer for the case of RPC_IS_SOFT(), since
|
|
* Note that we only set the timer for the case of RPC_IS_SOFT(), since
|
|
* we don't in general want to force a socket disconnection due to
|
|
* we don't in general want to force a socket disconnection due to
|
|
* an incomplete RPC call transmission.
|
|
* an incomplete RPC call transmission.
|
|
*/
|
|
*/
|
|
-void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action)
|
|
|
|
|
|
+void xprt_wait_for_buffer_space(struct rpc_xprt *xprt)
|
|
{
|
|
{
|
|
- struct rpc_rqst *req = task->tk_rqstp;
|
|
|
|
- struct rpc_xprt *xprt = req->rq_xprt;
|
|
|
|
-
|
|
|
|
- task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0;
|
|
|
|
- rpc_sleep_on(&xprt->pending, task, action);
|
|
|
|
|
|
+ set_bit(XPRT_WRITE_SPACE, &xprt->state);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
|
|
EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
|
|
|
|
|
|
|
|
+static bool
|
|
|
|
+xprt_clear_write_space_locked(struct rpc_xprt *xprt)
|
|
|
|
+{
|
|
|
|
+ if (test_and_clear_bit(XPRT_WRITE_SPACE, &xprt->state)) {
|
|
|
|
+ __xprt_lock_write_next(xprt);
|
|
|
|
+ dprintk("RPC: write space: waking waiting task on "
|
|
|
|
+ "xprt %p\n", xprt);
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* xprt_write_space - wake the task waiting for transport output buffer space
|
|
* xprt_write_space - wake the task waiting for transport output buffer space
|
|
* @xprt: transport with waiting tasks
|
|
* @xprt: transport with waiting tasks
|
|
*
|
|
*
|
|
* Can be called in a soft IRQ context, so xprt_write_space never sleeps.
|
|
* Can be called in a soft IRQ context, so xprt_write_space never sleeps.
|
|
*/
|
|
*/
|
|
-void xprt_write_space(struct rpc_xprt *xprt)
|
|
|
|
|
|
+bool xprt_write_space(struct rpc_xprt *xprt)
|
|
{
|
|
{
|
|
|
|
+ bool ret;
|
|
|
|
+
|
|
|
|
+ if (!test_bit(XPRT_WRITE_SPACE, &xprt->state))
|
|
|
|
+ return false;
|
|
spin_lock_bh(&xprt->transport_lock);
|
|
spin_lock_bh(&xprt->transport_lock);
|
|
- if (xprt->snd_task) {
|
|
|
|
- dprintk("RPC: write space: waking waiting task on "
|
|
|
|
- "xprt %p\n", xprt);
|
|
|
|
- rpc_wake_up_queued_task_on_wq(xprtiod_workqueue,
|
|
|
|
- &xprt->pending, xprt->snd_task);
|
|
|
|
- }
|
|
|
|
|
|
+ ret = xprt_clear_write_space_locked(xprt);
|
|
spin_unlock_bh(&xprt->transport_lock);
|
|
spin_unlock_bh(&xprt->transport_lock);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(xprt_write_space);
|
|
EXPORT_SYMBOL_GPL(xprt_write_space);
|
|
|
|
|
|
@@ -653,6 +671,7 @@ void xprt_disconnect_done(struct rpc_xprt *xprt)
|
|
dprintk("RPC: disconnected transport %p\n", xprt);
|
|
dprintk("RPC: disconnected transport %p\n", xprt);
|
|
spin_lock_bh(&xprt->transport_lock);
|
|
spin_lock_bh(&xprt->transport_lock);
|
|
xprt_clear_connected(xprt);
|
|
xprt_clear_connected(xprt);
|
|
|
|
+ xprt_clear_write_space_locked(xprt);
|
|
xprt_wake_pending_tasks(xprt, -EAGAIN);
|
|
xprt_wake_pending_tasks(xprt, -EAGAIN);
|
|
spin_unlock_bh(&xprt->transport_lock);
|
|
spin_unlock_bh(&xprt->transport_lock);
|
|
}
|
|
}
|
|
@@ -1326,9 +1345,7 @@ xprt_transmit(struct rpc_task *task)
|
|
if (!xprt_request_data_received(task) ||
|
|
if (!xprt_request_data_received(task) ||
|
|
test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
|
|
test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
|
|
continue;
|
|
continue;
|
|
- } else if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
|
|
|
|
- rpc_wake_up_queued_task(&xprt->pending, task);
|
|
|
|
- else
|
|
|
|
|
|
+ } else if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
|
|
task->tk_status = status;
|
|
task->tk_status = status;
|
|
break;
|
|
break;
|
|
}
|
|
}
|