]>
Commit | Line | Data |
---|---|---|
495c55a2 GKH |
1 | From b7e5034cbecf5a65b7bfdc2b20a8378039577706 Mon Sep 17 00:00:00 2001 |
2 | From: "J. Bruce Fields" <bfields@redhat.com> | |
3 | Date: Wed, 20 Feb 2019 12:54:50 -0500 | |
4 | Subject: svcrpc: fix UDP on servers with lots of threads | |
5 | ||
6 | From: J. Bruce Fields <bfields@redhat.com> | |
7 | ||
8 | commit b7e5034cbecf5a65b7bfdc2b20a8378039577706 upstream. | |
9 | ||
10 | James Pearson found that an NFS server stopped responding to UDP | |
11 | requests if started with more than 1017 threads. | |
12 | ||
13 | sv_max_mesg is about 2^20, so that is probably where the calculation | |
14 | performed by | |
15 | ||
16 | svc_sock_setbufsize(svsk->sk_sock, | |
17 | (serv->sv_nrthreads+3) * serv->sv_max_mesg, | |
18 | (serv->sv_nrthreads+3) * serv->sv_max_mesg); | |
19 | ||
20 | starts to overflow an int. | |
21 | ||
22 | Reported-by: James Pearson <jcpearson@gmail.com> | |
23 | Tested-by: James Pearson <jcpearson@gmail.com> | |
24 | Cc: stable@vger.kernel.org | |
25 | Signed-off-by: J. Bruce Fields <bfields@redhat.com> | |
26 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
27 | ||
28 | --- | |
29 | net/sunrpc/svcsock.c | 20 ++++++++++---------- | |
30 | 1 file changed, 10 insertions(+), 10 deletions(-) | |
31 | ||
32 | --- a/net/sunrpc/svcsock.c | |
33 | +++ b/net/sunrpc/svcsock.c | |
34 | @@ -381,12 +381,16 @@ static int svc_partial_recvfrom(struct s | |
35 | /* | |
36 | * Set socket snd and rcv buffer lengths | |
37 | */ | |
38 | -static void svc_sock_setbufsize(struct socket *sock, unsigned int snd, | |
39 | - unsigned int rcv) | |
40 | +static void svc_sock_setbufsize(struct svc_sock *svsk, unsigned int nreqs) | |
41 | { | |
42 | + unsigned int max_mesg = svsk->sk_xprt.xpt_server->sv_max_mesg; | |
43 | + struct socket *sock = svsk->sk_sock; | |
44 | + | |
45 | + nreqs = min(nreqs, INT_MAX / 2 / max_mesg); | |
46 | + | |
47 | lock_sock(sock->sk); | |
48 | - sock->sk->sk_sndbuf = snd * 2; | |
49 | - sock->sk->sk_rcvbuf = rcv * 2; | |
50 | + sock->sk->sk_sndbuf = nreqs * max_mesg * 2; | |
51 | + sock->sk->sk_rcvbuf = nreqs * max_mesg * 2; | |
52 | sock->sk->sk_write_space(sock->sk); | |
53 | release_sock(sock->sk); | |
54 | } | |
55 | @@ -548,9 +552,7 @@ static int svc_udp_recvfrom(struct svc_r | |
56 | * provides an upper bound on the number of threads | |
57 | * which will access the socket. | |
58 | */ | |
59 | - svc_sock_setbufsize(svsk->sk_sock, | |
60 | - (serv->sv_nrthreads+3) * serv->sv_max_mesg, | |
61 | - (serv->sv_nrthreads+3) * serv->sv_max_mesg); | |
62 | + svc_sock_setbufsize(svsk, serv->sv_nrthreads + 3); | |
63 | ||
64 | clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | |
65 | skb = NULL; | |
66 | @@ -718,9 +720,7 @@ static void svc_udp_init(struct svc_sock | |
67 | * receive and respond to one request. | |
68 | * svc_udp_recvfrom will re-adjust if necessary | |
69 | */ | |
70 | - svc_sock_setbufsize(svsk->sk_sock, | |
71 | - 3 * svsk->sk_xprt.xpt_server->sv_max_mesg, | |
72 | - 3 * svsk->sk_xprt.xpt_server->sv_max_mesg); | |
73 | + svc_sock_setbufsize(svsk, 3); | |
74 | ||
75 | /* data might have come in before data_ready set up */ | |
76 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); |