Commit 3060e011 authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] Rearrange setting of snd/rcv buf size to avoid locking issue

Currently svc_sock_setbuf can be called under a spinlock,
but it can try to lock a socket, which can block....

Now when we decide that changing the size might be good we
set a flag (SK_CHNGBUF) and then later (when the next
packet arrives) we change the sizes appropriately.
parent d1269ac7
...@@ -30,6 +30,7 @@ struct svc_sock { ...@@ -30,6 +30,7 @@ struct svc_sock {
#define SK_TEMP 4 /* temp (TCP) socket */ #define SK_TEMP 4 /* temp (TCP) socket */
#define SK_QUED 5 /* on serv->sk_sockets */ #define SK_QUED 5 /* on serv->sk_sockets */
#define SK_DEAD 6 /* socket closed */ #define SK_DEAD 6 /* socket closed */
#define SK_CHNGBUF 7 /* need to change snd/rcv buffer sizes */
int sk_reserved; /* space on outq that is reserved */ int sk_reserved; /* space on outq that is reserved */
......
...@@ -481,6 +481,16 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) ...@@ -481,6 +481,16 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
u32 *data; u32 *data;
int err, len; int err, len;
if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
/* udp sockets need large rcvbuf as all pending
* requests are still in that buffer. sndbuf must
* also be large enough that there is enough space
* for one reply per thread.
*/
svc_sock_setbufsize(svsk->sk_sock,
(serv->sv_nrthreads+3) * serv->sv_bufsz,
(serv->sv_nrthreads+3) * serv->sv_bufsz);
clear_bit(SK_DATA, &svsk->sk_flags); clear_bit(SK_DATA, &svsk->sk_flags);
while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
svc_sock_received(svsk); svc_sock_received(svsk);
...@@ -564,6 +574,8 @@ svc_udp_init(struct svc_sock *svsk) ...@@ -564,6 +574,8 @@ svc_udp_init(struct svc_sock *svsk)
svsk->sk_recvfrom = svc_udp_recvfrom; svsk->sk_recvfrom = svc_udp_recvfrom;
svsk->sk_sendto = svc_udp_sendto; svsk->sk_sendto = svc_udp_sendto;
set_bit(SK_CHNGBUF, &svsk->sk_flags);
return 0; return 0;
} }
...@@ -771,6 +783,18 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) ...@@ -771,6 +783,18 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
return 0; return 0;
} }
if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
/* sndbuf needs to have room for one request
* per thread, otherwise we can stall even when the
* network isn't a bottleneck.
* rcvbuf just needs to be able to hold a few requests.
* Normally they will be removed from the queue
* as soon a a complete request arrives.
*/
svc_sock_setbufsize(svsk->sk_sock,
(serv->sv_nrthreads+3) * serv->sv_bufsz,
3 * serv->sv_bufsz);
clear_bit(SK_DATA, &svsk->sk_flags); clear_bit(SK_DATA, &svsk->sk_flags);
/* Receive data. If we haven't got the record length yet, get /* Receive data. If we haven't got the record length yet, get
...@@ -916,17 +940,7 @@ svc_tcp_init(struct svc_sock *svsk) ...@@ -916,17 +940,7 @@ svc_tcp_init(struct svc_sock *svsk)
svsk->sk_reclen = 0; svsk->sk_reclen = 0;
svsk->sk_tcplen = 0; svsk->sk_tcplen = 0;
/* sndbuf needs to have room for one request set_bit(SK_CHNGBUF, &svsk->sk_flags);
* per thread, otherwise we can stall even when the
* network isn't a bottleneck.
* rcvbuf just needs to be able to hold a few requests.
* Normally they will be removed from the queue
* as soon a a complete request arrives.
*/
svc_sock_setbufsize(svsk->sk_sock,
(svsk->sk_server->sv_nrthreads+3) *
svsk->sk_server->sv_bufsz,
3 * svsk->sk_server->sv_bufsz);
} }
return 0; return 0;
...@@ -945,30 +959,12 @@ svc_sock_update_bufs(struct svc_serv *serv) ...@@ -945,30 +959,12 @@ svc_sock_update_bufs(struct svc_serv *serv)
list_for_each(le, &serv->sv_permsocks) { list_for_each(le, &serv->sv_permsocks) {
struct svc_sock *svsk = struct svc_sock *svsk =
list_entry(le, struct svc_sock, sk_list); list_entry(le, struct svc_sock, sk_list);
struct socket *sock = svsk->sk_sock; set_bit(SK_CHNGBUF, &svsk->sk_flags);
if (sock->type == SOCK_DGRAM) {
/* udp sockets need large rcvbuf as all pending
* requests are still in that buffer.
*/
svc_sock_setbufsize(sock,
(serv->sv_nrthreads+3) * serv->sv_bufsz,
(serv->sv_nrthreads+3) * serv->sv_bufsz);
} else if (svsk->sk_sk->state != TCP_LISTEN) {
printk(KERN_ERR "RPC update_bufs: permanent sock neither UDP or TCP_LISTEN\n");
}
} }
list_for_each(le, &serv->sv_tempsocks) { list_for_each(le, &serv->sv_tempsocks) {
struct svc_sock *svsk = struct svc_sock *svsk =
list_entry(le, struct svc_sock, sk_list); list_entry(le, struct svc_sock, sk_list);
struct socket *sock = svsk->sk_sock; set_bit(SK_CHNGBUF, &svsk->sk_flags);
if (sock->type == SOCK_STREAM) {
/* See svc_tcp_init above for rationale on buffer sizes */
svc_sock_setbufsize(sock,
(serv->sv_nrthreads+3) *
serv->sv_bufsz,
3 * serv->sv_bufsz);
} else
printk(KERN_ERR "RPC update_bufs: temp sock not TCP\n");
} }
spin_unlock_bh(&serv->sv_lock); spin_unlock_bh(&serv->sv_lock);
} }
......
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