Commit b7e5034c authored by J. Bruce Fields's avatar J. Bruce Fields

svcrpc: fix UDP on servers with lots of threads

James Pearson found that an NFS server stopped responding to UDP
requests if started with more than 1017 threads.

sv_max_mesg is about 2^20, so that is probably where the calculation
performed by

	svc_sock_setbufsize(svsk->sk_sock,
                            (serv->sv_nrthreads+3) * serv->sv_max_mesg,
                            (serv->sv_nrthreads+3) * serv->sv_max_mesg);

starts to overflow an int.
Reported-by: default avatarJames Pearson <jcpearson@gmail.com>
Tested-by: default avatarJames Pearson <jcpearson@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 8820bcaa
...@@ -349,12 +349,16 @@ static ssize_t svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, ...@@ -349,12 +349,16 @@ static ssize_t svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov,
/* /*
* Set socket snd and rcv buffer lengths * Set socket snd and rcv buffer lengths
*/ */
static void svc_sock_setbufsize(struct socket *sock, unsigned int snd, static void svc_sock_setbufsize(struct svc_sock *svsk, unsigned int nreqs)
unsigned int rcv)
{ {
unsigned int max_mesg = svsk->sk_xprt.xpt_server->sv_max_mesg;
struct socket *sock = svsk->sk_sock;
nreqs = min(nreqs, INT_MAX / 2 / max_mesg);
lock_sock(sock->sk); lock_sock(sock->sk);
sock->sk->sk_sndbuf = snd * 2; sock->sk->sk_sndbuf = nreqs * max_mesg * 2;
sock->sk->sk_rcvbuf = rcv * 2; sock->sk->sk_rcvbuf = nreqs * max_mesg * 2;
sock->sk->sk_write_space(sock->sk); sock->sk->sk_write_space(sock->sk);
release_sock(sock->sk); release_sock(sock->sk);
} }
...@@ -516,9 +520,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) ...@@ -516,9 +520,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
* provides an upper bound on the number of threads * provides an upper bound on the number of threads
* which will access the socket. * which will access the socket.
*/ */
svc_sock_setbufsize(svsk->sk_sock, svc_sock_setbufsize(svsk, serv->sv_nrthreads + 3);
(serv->sv_nrthreads+3) * serv->sv_max_mesg,
(serv->sv_nrthreads+3) * serv->sv_max_mesg);
clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
skb = NULL; skb = NULL;
...@@ -681,9 +683,7 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) ...@@ -681,9 +683,7 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
* receive and respond to one request. * receive and respond to one request.
* svc_udp_recvfrom will re-adjust if necessary * svc_udp_recvfrom will re-adjust if necessary
*/ */
svc_sock_setbufsize(svsk->sk_sock, svc_sock_setbufsize(svsk, 3);
3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
/* data might have come in before data_ready set up */ /* data might have come in before data_ready set up */
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
......
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