Blob Blame History Raw
From f5e317a62939f1b06081f309ee4e7b146385509b Mon Sep 17 00:00:00 2001
Message-Id: <f5e317a62939f1b06081f309ee4e7b146385509b.1377873636.git.jdenemar@redhat.com>
From: Michal Privoznik <mprivozn@redhat.com>
Date: Mon, 5 Aug 2013 11:30:16 +0200
Subject: [PATCH] RPC: Don't accept client if it would overcommit max_clients

https://bugzilla.redhat.com/show_bug.cgi?id=981729

Currently, even if max_client limit is hit, we accept() incoming
connection request, but close it immediately. This has disadvantage of
not using listen() queue. We should accept() only those clients we
know we can serve and let all other wait in the (limited) queue.
(cherry picked from commit 2737aaafe953fc63c3387aa3ecc540b0f44c735c)
---
 src/rpc/virnetserver.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index cb770c3..2306e10 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -115,6 +115,8 @@ struct _virNetServer {
 
 static virClassPtr virNetServerClass;
 static void virNetServerDispose(void *obj);
+static void virNetServerUpdateServicesLocked(virNetServerPtr srv,
+                                             bool enabled);
 
 static int virNetServerOnceInit(void)
 {
@@ -270,6 +272,12 @@ static int virNetServerAddClient(virNetServerPtr srv,
     srv->clients[srv->nclients-1] = client;
     virObjectRef(client);
 
+    if (srv->nclients == srv->nclients_max) {
+        /* Temporarily stop accepting new clients */
+        VIR_DEBUG("Temporarily suspending services due to max_clients");
+        virNetServerUpdateServicesLocked(srv, false);
+    }
+
     virNetServerClientSetDispatcher(client,
                                     virNetServerDispatchNewMessage,
                                     srv);
@@ -1034,15 +1042,22 @@ static void virNetServerAutoShutdownTimer(int timerid ATTRIBUTE_UNUSED,
 }
 
 
-void virNetServerUpdateServices(virNetServerPtr srv,
-                                bool enabled)
+static void
+virNetServerUpdateServicesLocked(virNetServerPtr srv,
+                                 bool enabled)
 {
     size_t i;
 
-    virObjectLock(srv);
     for (i = 0; i < srv->nservices; i++)
         virNetServerServiceToggle(srv->services[i], enabled);
+}
 
+
+void virNetServerUpdateServices(virNetServerPtr srv,
+                                bool enabled)
+{
+    virObjectLock(srv);
+    virNetServerUpdateServicesLocked(srv, enabled);
     virObjectUnlock(srv);
 }
 
@@ -1120,6 +1135,14 @@ void virNetServerRun(virNetServerPtr srv)
                     srv->nclients = 0;
                 }
 
+                /* Enable services if we can accept a new client.
+                 * The new client can be accepted if we are at the limit. */
+                if (srv->nclients == srv->nclients_max - 1) {
+                    /* Now it makes sense to accept() a new client. */
+                    VIR_DEBUG("Re-enabling services");
+                    virNetServerUpdateServicesLocked(srv, true);
+                }
+
                 virObjectUnlock(srv);
                 virObjectUnref(client);
                 virObjectLock(srv);
-- 
1.8.3.2