Skip to content

Commit

Permalink
SUNRPC: Fix up xprt_write_space()
Browse files Browse the repository at this point in the history
The rest of the networking layer uses SOCK_ASYNC_NOSPACE to signal whether
or not we have someone waiting for buffer memory. Convert the SUNRPC layer
to use the same idiom.
Remove the unlikely()s in xs_udp_write_space and xs_tcp_write_space. In
fact, the most common case will be that there is nobody waiting for buffer
space.

SOCK_NOSPACE is there to tell the TCP layer whether or not the cwnd was
limited by the application window. Ensure that we follow the same idiom as
the rest of the networking layer here too.

Finally, ensure that we clear SOCK_ASYNC_NOSPACE once we wake up, so that
write_space() doesn't keep waking things up on xprt->pending.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Apr 19, 2008
1 parent 24b74bf commit b6ddf64
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 23 deletions.
2 changes: 1 addition & 1 deletion include/linux/sunrpc/xprt.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ int xprt_unregister_transport(struct xprt_class *type);
void xprt_set_retrans_timeout_def(struct rpc_task *task);
void xprt_set_retrans_timeout_rtt(struct rpc_task *task);
void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
void xprt_wait_for_buffer_space(struct rpc_task *task);
void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action);
void xprt_write_space(struct rpc_xprt *xprt);
void xprt_update_rtt(struct rpc_task *task);
void xprt_adjust_cwnd(struct rpc_task *task, int result);
Expand Down
4 changes: 2 additions & 2 deletions net/sunrpc/xprt.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,13 +447,13 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
* @task: task to be put to sleep
*
*/
void xprt_wait_for_buffer_space(struct rpc_task *task)
void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action)
{
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = req->rq_xprt;

task->tk_timeout = req->rq_timeout;
rpc_sleep_on(&xprt->pending, task, NULL);
rpc_sleep_on(&xprt->pending, task, action);
}
EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);

Expand Down
61 changes: 41 additions & 20 deletions net/sunrpc/xprtsock.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,14 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
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
* @task: task to put to sleep
Expand All @@ -531,20 +539,27 @@ static void xs_nospace(struct rpc_task *task)
task->tk_pid, req->rq_slen - req->rq_bytes_sent,
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);
}

/**
Expand Down Expand Up @@ -588,19 +603,20 @@ static int xs_udp_send_request(struct rpc_task *task)
}

switch (status) {
case -EAGAIN:
xs_nospace(task);
break;
case -ENETUNREACH:
case -EPIPE:
case -ECONNREFUSED:
/* When the server has died, an ICMP port unreachable message
* prompts ECONNREFUSED. */
break;
case -EAGAIN:
xs_nospace(task);
clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
break;
default:
clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
break;
}

return status;
Expand Down Expand Up @@ -695,12 +711,13 @@ static int xs_tcp_send_request(struct rpc_task *task)
case -ENOTCONN:
case -EPIPE:
status = -ENOTCONN;
clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
break;
default:
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
xs_tcp_shutdown(xprt);
break;
}

return status;
Expand Down Expand Up @@ -1189,9 +1206,11 @@ static void xs_udp_write_space(struct sock *sk)

if (unlikely(!(sock = sk->sk_socket)))
goto out;
clear_bit(SOCK_NOSPACE, &sock->flags);

if (unlikely(!(xprt = xprt_from_sock(sk))))
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;

xprt_write_space(xprt);
Expand Down Expand Up @@ -1222,9 +1241,11 @@ static void xs_tcp_write_space(struct sock *sk)

if (unlikely(!(sock = sk->sk_socket)))
goto out;
clear_bit(SOCK_NOSPACE, &sock->flags);

if (unlikely(!(xprt = xprt_from_sock(sk))))
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;

xprt_write_space(xprt);
Expand Down

0 comments on commit b6ddf64

Please sign in to comment.