2008-06-10 18:54:46

by Dean

[permalink] [raw]
Subject: [PATCH 1/1] SUNRPC: Add sysctl variables for server TCP snd/rcv buffer values.

Introduce 2 sysctl variables to allow users to set
larger values of the tcp send and receive buffer sizes,
i.e., SO_SNDBUF and SO_RCVBUF. Client tcp connections
(and the associated tcp window) will reflrect updated
values when the server is mounted.

Signed-off-by: Dean Hildebrand <[email protected]>
---
net/sunrpc/svcsock.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 110 insertions(+), 5 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 3e65719..7f14e4a 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -53,6 +53,62 @@
#define RPCDBG_FACILITY RPCDBG_SVCXPRT


+unsigned int svc_tcp_sndbuf;
+unsigned int svc_tcp_rcvbuf;
+
+#ifdef RPC_DEBUG
+
+/* Setting to 0 resets value to default */
+static unsigned int svc_min_tcpbuf;
+/* Ensure large enough not to restrict most environments.
+ * Real maximum is determined by sysctl default TCP buffer values. */
+static unsigned int svc_max_tcpbuf = (1024 * RPCSVC_MAXPAYLOAD_TCP);
+
+static struct ctl_table_header *sunrpc_table_header;
+
+/* Client specific sysctl entries */
+static ctl_table svc_tunables_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "tcp_sndbuf",
+ .data = &svc_tcp_sndbuf,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &svc_min_tcpbuf,
+ .extra2 = &svc_max_tcpbuf
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "tcp_rcvbuf",
+ .data = &svc_tcp_rcvbuf,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &svc_min_tcpbuf,
+ .extra2 = &svc_max_tcpbuf
+ },
+ {
+ .ctl_name = 0,
+ },
+};
+
+static ctl_table sunrpc_table[] = {
+ {
+ .ctl_name = CTL_SUNRPC,
+ .procname = "sunrpc",
+ .mode = 0555,
+ .child = svc_tunables_table
+ },
+ {
+ .ctl_name = 0,
+ },
+};
+
+#endif
+
static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
int *errp, int flags);
static void svc_udp_data_ready(struct sock *, int);
@@ -96,6 +152,44 @@ static void svc_reclassify_socket(struct socket *sock)
}
#endif

+static inline unsigned int
+svc_get_tcp_snd_buf(struct svc_serv *serv)
+{
+ unsigned int startsize = 3 * serv->sv_max_mesg;
+ unsigned int minsize = (serv->sv_nrthreads+3) * serv->sv_max_mesg;
+ unsigned int result;
+
+ /* Ensure caller cannot set buf size below minimum required */
+ if (!svc_tcp_sndbuf)
+ result = startsize;
+ else
+ result = max(svc_tcp_sndbuf, minsize);
+
+ /* update proc variable */
+ svc_tcp_sndbuf = result;
+
+ dprintk("%s: sndbuf %u (min %u)\n", __func__, result, minsize);
+
+ return result;
+}
+
+static inline unsigned int
+svc_get_tcp_rcv_buf(struct svc_serv *serv)
+{
+ unsigned int minsize = 3 * serv->sv_max_mesg;
+ unsigned int result;
+
+ /* Ensure caller cannot set buf size below minimum required */
+ result = max(svc_tcp_rcvbuf, minsize);
+
+ /* update proc variable */
+ svc_tcp_rcvbuf = result;
+
+ dprintk("%s: rcvbuf %d (min %u)\n", __func__, result, minsize);
+
+ return result;
+}
+
/*
* Release an skbuff after use
*/
@@ -814,9 +908,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
* 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_max_mesg,
- 3 * serv->sv_max_mesg);
+ svc_sock_setbufsize(svsk->sk_sock, svc_get_tcp_snd_buf(serv),
+ svc_get_tcp_rcv_buf(serv));

clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);

@@ -1033,12 +1126,24 @@ static struct svc_xprt_class svc_tcp_class = {

void svc_init_xprt_sock(void)
{
+#ifdef RPC_DEBUG
+ if (!sunrpc_table_header)
+ sunrpc_table_header = register_sysctl_table(sunrpc_table);
+#endif
+
svc_reg_xprt_class(&svc_tcp_class);
svc_reg_xprt_class(&svc_udp_class);
}

void svc_cleanup_xprt_sock(void)
{
+#ifdef RPC_DEBUG
+ if (sunrpc_table_header) {
+ unregister_sysctl_table(sunrpc_table_header);
+ sunrpc_table_header = NULL;
+ }
+#endif
+
svc_unreg_xprt_class(&svc_tcp_class);
svc_unreg_xprt_class(&svc_udp_class);
}
@@ -1070,8 +1175,8 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
* svc_tcp_recvfrom will re-adjust if necessary
*/
svc_sock_setbufsize(svsk->sk_sock,
- 3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
- 3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
+ svc_get_tcp_snd_buf(svsk->sk_xprt.xpt_server),
+ svc_get_tcp_rcv_buf(svsk->sk_xprt.xpt_server));

set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
--
1.5.3.3