[libvirt] [PATCH 1/2] RPC: Don't accept client if it would overcommit max_clients
Daniel P. Berrange
berrange at redhat.com
Thu Jul 25 14:37:29 UTC 2013
On Thu, Jul 25, 2013 at 04:23:32PM +0200, Michal Privoznik wrote:
> 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.
> ---
> src/rpc/virnetserver.c | 40 ++++++++++++++++++++++++++++++++++++++++
> src/rpc/virnetserverservice.c | 9 +++++++++
> src/rpc/virnetserverservice.h | 4 ++++
> 3 files changed, 53 insertions(+)
>
> diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
> index cb770c3..7ea1707 100644
> --- a/src/rpc/virnetserver.c
> +++ b/src/rpc/virnetserver.c
> @@ -315,6 +315,34 @@ static int virNetServerDispatchNewClient(virNetServerServicePtr svc,
> }
>
>
> +static int
> +virNetServerDispatchCheck(virNetServerServicePtr svc,
> + virNetSocketPtr socket,
> + void *opaque)
> +{
> + virNetServerPtr srv = opaque;
> + int ret = -1;
> +
> + VIR_DEBUG("svc=%p socket=%p opaque=%p", svc, socket, opaque);
> +
> + if (srv->nclients >= srv->nclients_max) {
> + VIR_DEBUG("Not accepting client now due to max_clients setting (%zu)",
> + srv->nclients_max);
> +
> + /* We need to temporarily disable the server services in order to
> + * prevent event loop calling us over and over again. */
> +
> + virNetServerUpdateServices(srv, false);
> +
> + goto cleanup;
> + }
> +
> + ret = 0;
> +cleanup:
> + return ret;
> +}
> +
> +
> static void
> virNetServerFatalSignal(int sig, siginfo_t *siginfo ATTRIBUTE_UNUSED,
> void *context ATTRIBUTE_UNUSED)
> @@ -981,6 +1009,7 @@ int virNetServerAddService(virNetServerPtr srv,
>
> virNetServerServiceSetDispatcher(svc,
> virNetServerDispatchNewClient,
> + virNetServerDispatchCheck,
> srv);
>
> virObjectUnlock(srv);
> @@ -1110,6 +1139,8 @@ void virNetServerRun(virNetServerPtr srv)
> virNetServerClientClose(srv->clients[i]);
> if (virNetServerClientIsClosed(srv->clients[i])) {
> virNetServerClientPtr client = srv->clients[i];
> + bool update_services;
> +
> if (srv->nclients > 1) {
> memmove(srv->clients + i,
> srv->clients + i + 1,
> @@ -1120,7 +1151,16 @@ 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. */
> + update_services = srv->nclients == srv->nclients_max - 1;
> +
> virObjectUnlock(srv);
> + if (update_services) {
> + /* Now it makes sense to accept() a new client. */
> + VIR_DEBUG("Re-enabling services");
> + virNetServerUpdateServices(srv, true);
> + }
> virObjectUnref(client);
> virObjectLock(srv);
>
> diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c
> index 632f03d..a47c8f8 100644
> --- a/src/rpc/virnetserverservice.c
> +++ b/src/rpc/virnetserverservice.c
> @@ -46,6 +46,7 @@ struct _virNetServerService {
> #endif
>
> virNetServerServiceDispatchFunc dispatchFunc;
> + virNetServerServiceDispatchCheckFunc dispatchCheckFunc;
> void *dispatchOpaque;
> };
>
> @@ -74,6 +75,12 @@ static void virNetServerServiceAccept(virNetSocketPtr sock,
> virNetServerServicePtr svc = opaque;
> virNetSocketPtr clientsock = NULL;
>
> + if (svc->dispatchCheckFunc &&
> + svc->dispatchCheckFunc(svc, sock, svc->dispatchOpaque) < 0) {
> + /* Accept declined */
> + goto cleanup;
> + }
> +
Rather than having this callback, can we not simply change virNetServerAddClient()
to call virNetServerUpdateServices(srv, false); when a new client causes us to hit
the max limit ?
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list