Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > media > main-src > by-pkgid > d0a35cd31c1125e2132804d68547073d > files > 2706

kernel-2.6.18-194.26.1.el5.src.rpm

From: Jeff Layton <jlayton@redhat.com>
Date: Mon, 15 Dec 2008 13:35:05 -0500
Subject: [nfs] sunrpc: add sv_maxconn field to svc_serv
Message-id: 1229366106-23523-2-git-send-email-jlayton@redhat.com
O-Subject: [RHEL5.4 PATCH 1/2] BZ#468092: sunrpc: add sv_maxconn field to svc_serv
Bugzilla: 468092

svc_tcp_accept() attempts to prevent denial of service attacks
by having the service close old connections once it reaches a
threshold. This threshold is based on the number of threads in the
service:

        (serv->sv_nrthreads + 3) * 20

Once we reach this, we drop the oldest connections and a printk pops
to warn the admin that they should increase the number of nfsd threads.

Increasing the number of threads isn't an option however for services
like lockd. We don't want to eliminate this check entirely for such
services but we need some way to increase this limit.

This patch adds a sv_maxconn field to the svc_serv struct. When it's
set to 0, we use the current method to calculate the max number of
connections. RPC services can then set this on an as-needed basis.

Signed-off-by: Jeff Layton <jlayton@redhat.com>

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 3ff4e6e..ecede8b 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -44,9 +44,12 @@ struct svc_serv {
 	char *			sv_name;	/* service name */
 #ifndef __GENKSYMS__
 	void			(*sv_shutdown)(struct svc_serv *serv);
-						/* Callback to use when last thread
-						 * exits.
+						/* Callback to use when last
+						 * thread exits.
 						 */
+	unsigned int		sv_maxconn;	/* max connections allowed or
+						 * '0' causing max to be based
+						 * on number of threads. */
 #endif
 };
 
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 0a736d8..99f0919 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -839,6 +839,7 @@ svc_tcp_accept(struct svc_sock *svsk)
 	struct socket	*newsock;
 	struct svc_sock	*newsvsk;
 	int		err, slen;
+	unsigned int	limit;
 
 	dprintk("svc: tcp_accept %p sock %p\n", svsk, sock);
 	if (!sock)
@@ -891,8 +892,11 @@ svc_tcp_accept(struct svc_sock *svsk)
 		goto failed;
 
 
-	/* make sure that we don't have too many active connections.
-	 * If we have, something must be dropped.
+	/* make sure that we don't have too many active connections. If we
+	 * have, something must be dropped. It's not clear what will happen if
+	 * we allow "too many" connections, but when dealing with
+	 * network-facing software, we have to code defensively. Here we do
+	 * that by imposing hard limits.
 	 *
 	 * There's no point in trying to do random drop here for
 	 * DoS prevention. The NFS clients does 1 reconnect in 15
@@ -901,17 +905,24 @@ svc_tcp_accept(struct svc_sock *svsk)
 	 * The only somewhat efficient mechanism would be if drop
 	 * old connections from the same IP first. But right now
 	 * we don't even record the client IP in svc_sock.
+	 *
+	 * single-threaded services that expect a lot of clients will probably
+	 * need to set sv_maxconn to override the default value which is based
+	 * on the number of threads
 	 */
-	if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
+	limit = serv->sv_maxconn ? serv->sv_maxconn :
+		(serv->sv_nrthreads+3) * 20;
+	if (serv->sv_tmpcnt > limit) {
 		struct svc_sock *svsk = NULL;
 		spin_lock_bh(&serv->sv_lock);
 		if (!list_empty(&serv->sv_tempsocks)) {
 			if (net_ratelimit()) {
 				/* Try to help the admin */
 				printk(KERN_NOTICE "%s: too many open TCP "
-					"sockets, consider increasing the "
-					"number of nfsd threads\n",
-						   serv->sv_name);
+					"connections, consider increasing %s\n",
+					serv->sv_name, serv->sv_maxconn ?
+					"the max number of connections." :
+					"the number of threads.");
 				printk(KERN_NOTICE "%s: last TCP connect from "
 					"%u.%u.%u.%u:%d\n",
 					serv->sv_name,