|
@@ -516,6 +516,14 @@ out:
|
|
return sent;
|
|
return sent;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void xs_nospace_callback(struct rpc_task *task)
|
|
|
|
+{
|
|
|
|
+ struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
|
|
|
|
+
|
|
|
|
+ transport->inet->sk_write_pending--;
|
|
|
|
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* xs_nospace - place task on wait queue if transmit was incomplete
|
|
* xs_nospace - place task on wait queue if transmit was incomplete
|
|
* @task: task to put to sleep
|
|
* @task: task to put to sleep
|
|
@@ -531,20 +539,27 @@ static void xs_nospace(struct rpc_task *task)
|
|
task->tk_pid, req->rq_slen - req->rq_bytes_sent,
|
|
task->tk_pid, req->rq_slen - req->rq_bytes_sent,
|
|
req->rq_slen);
|
|
req->rq_slen);
|
|
|
|
|
|
- if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
|
|
|
|
- /* Protect against races with write_space */
|
|
|
|
- spin_lock_bh(&xprt->transport_lock);
|
|
|
|
-
|
|
|
|
- /* Don't race with disconnect */
|
|
|
|
- if (!xprt_connected(xprt))
|
|
|
|
- task->tk_status = -ENOTCONN;
|
|
|
|
- else if (test_bit(SOCK_NOSPACE, &transport->sock->flags))
|
|
|
|
- xprt_wait_for_buffer_space(task);
|
|
|
|
|
|
+ /* Protect against races with write_space */
|
|
|
|
+ spin_lock_bh(&xprt->transport_lock);
|
|
|
|
+
|
|
|
|
+ /* Don't race with disconnect */
|
|
|
|
+ if (xprt_connected(xprt)) {
|
|
|
|
+ if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
|
|
|
|
+ /*
|
|
|
|
+ * Notify TCP that we're limited by the application
|
|
|
|
+ * window size
|
|
|
|
+ */
|
|
|
|
+ set_bit(SOCK_NOSPACE, &transport->sock->flags);
|
|
|
|
+ transport->inet->sk_write_pending++;
|
|
|
|
+ /* ...and wait for more buffer space */
|
|
|
|
+ xprt_wait_for_buffer_space(task, xs_nospace_callback);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
|
|
|
|
+ task->tk_status = -ENOTCONN;
|
|
|
|
+ }
|
|
|
|
|
|
- spin_unlock_bh(&xprt->transport_lock);
|
|
|
|
- } else
|
|
|
|
- /* Keep holding the socket if it is blocked */
|
|
|
|
- rpc_delay(task, HZ>>4);
|
|
|
|
|
|
+ spin_unlock_bh(&xprt->transport_lock);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -588,19 +603,20 @@ static int xs_udp_send_request(struct rpc_task *task)
|
|
}
|
|
}
|
|
|
|
|
|
switch (status) {
|
|
switch (status) {
|
|
|
|
+ case -EAGAIN:
|
|
|
|
+ xs_nospace(task);
|
|
|
|
+ break;
|
|
case -ENETUNREACH:
|
|
case -ENETUNREACH:
|
|
case -EPIPE:
|
|
case -EPIPE:
|
|
case -ECONNREFUSED:
|
|
case -ECONNREFUSED:
|
|
/* When the server has died, an ICMP port unreachable message
|
|
/* When the server has died, an ICMP port unreachable message
|
|
* prompts ECONNREFUSED. */
|
|
* prompts ECONNREFUSED. */
|
|
- break;
|
|
|
|
- case -EAGAIN:
|
|
|
|
- xs_nospace(task);
|
|
|
|
|
|
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
|
|
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
|
|
dprintk("RPC: sendmsg returned unrecognized error %d\n",
|
|
dprintk("RPC: sendmsg returned unrecognized error %d\n",
|
|
-status);
|
|
-status);
|
|
- break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return status;
|
|
return status;
|
|
@@ -695,12 +711,13 @@ static int xs_tcp_send_request(struct rpc_task *task)
|
|
case -ENOTCONN:
|
|
case -ENOTCONN:
|
|
case -EPIPE:
|
|
case -EPIPE:
|
|
status = -ENOTCONN;
|
|
status = -ENOTCONN;
|
|
|
|
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
dprintk("RPC: sendmsg returned unrecognized error %d\n",
|
|
dprintk("RPC: sendmsg returned unrecognized error %d\n",
|
|
-status);
|
|
-status);
|
|
|
|
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
|
|
xs_tcp_shutdown(xprt);
|
|
xs_tcp_shutdown(xprt);
|
|
- break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return status;
|
|
return status;
|
|
@@ -1189,9 +1206,11 @@ static void xs_udp_write_space(struct sock *sk)
|
|
|
|
|
|
if (unlikely(!(sock = sk->sk_socket)))
|
|
if (unlikely(!(sock = sk->sk_socket)))
|
|
goto out;
|
|
goto out;
|
|
|
|
+ clear_bit(SOCK_NOSPACE, &sock->flags);
|
|
|
|
+
|
|
if (unlikely(!(xprt = xprt_from_sock(sk))))
|
|
if (unlikely(!(xprt = xprt_from_sock(sk))))
|
|
goto out;
|
|
goto out;
|
|
- if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)))
|
|
|
|
|
|
+ if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
xprt_write_space(xprt);
|
|
xprt_write_space(xprt);
|
|
@@ -1222,9 +1241,11 @@ static void xs_tcp_write_space(struct sock *sk)
|
|
|
|
|
|
if (unlikely(!(sock = sk->sk_socket)))
|
|
if (unlikely(!(sock = sk->sk_socket)))
|
|
goto out;
|
|
goto out;
|
|
|
|
+ clear_bit(SOCK_NOSPACE, &sock->flags);
|
|
|
|
+
|
|
if (unlikely(!(xprt = xprt_from_sock(sk))))
|
|
if (unlikely(!(xprt = xprt_from_sock(sk))))
|
|
goto out;
|
|
goto out;
|
|
- if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)))
|
|
|
|
|
|
+ if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
xprt_write_space(xprt);
|
|
xprt_write_space(xprt);
|