]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
util: fix libvirtd startup failure due to netlink error
authorLaine Stump <laine@laine.org>
Thu, 3 May 2012 14:39:04 +0000 (10:39 -0400)
committerCole Robinson <crobinso@redhat.com>
Thu, 14 Jun 2012 15:31:00 +0000 (11:31 -0400)
This is part of the solution to the problem detailed in:

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

and further detailed in

  https://www.redhat.com/archives/libvir-list/2012-May/msg00202.htm

A short explanation is included in the comments of the patch itself.

Note that this patch by itself breaks communication between lldpad and
libvirtd, so the other 3 patches in the series must be applied at the
same time as this patch.
(cherry picked from commit 642973135c54b93242c4548ef27d591b52b0994c)

Conflicts:

daemon/libvirtd.c

daemon/libvirtd.c
src/libvirt_private.syms
src/util/virnetlink.c
src/util/virnetlink.h

index 1ffbfbbd33f90dcc8afe2342d72ed7f4ead93e6a..19729f478d85dec89979a7e94ab7dcfc9713aaca 100644 (file)
@@ -1483,6 +1483,12 @@ int main(int argc, char **argv) {
 
     use_polkit_dbus = config->auth_unix_rw == REMOTE_AUTH_POLKIT ||
             config->auth_unix_ro == REMOTE_AUTH_POLKIT;
+
+    if (virNetlinkStartup() < 0) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
     if (!(srv = virNetServerNew(config->min_workers,
                                 config->max_workers,
                                 config->prio_workers,
@@ -1620,6 +1626,7 @@ cleanup:
     virNetServerProgramFree(qemuProgram);
     virNetServerClose(srv);
     virNetServerFree(srv);
+    virNetlinkShutdown();
     if (statuswrite != -1) {
         if (ret != 0) {
             /* Tell parent of daemon what failed */
index e3020e0e0ec9d53ffa16323937be13287badcb53..6fcdd874a9f2488f99c3275528dd10cfc26462c9 100644 (file)
@@ -1327,6 +1327,8 @@ virNetlinkEventRemoveClient;
 virNetlinkEventServiceIsRunning;
 virNetlinkEventServiceStop;
 virNetlinkEventServiceStart;
+virNetlinkShutdown;
+virNetlinkStartup;
 
 
 # virnetmessage.h
index a5e6ca9724301fea62ccff9146eb653a70486952..3577ecc9da1a36507254fce73b8d8dd85d43f41b 100644 (file)
@@ -88,9 +88,62 @@ static int nextWatch = 1;
 # define NETLINK_EVENT_ALLOC_EXTENT 10
 
 static virNetlinkEventSrvPrivatePtr server = NULL;
+static struct nl_handle *placeholder_nlhandle = NULL;
 
 /* Function definitions */
 
+/**
+ * virNetlinkStartup:
+ *
+ * Perform any initialization that needs to take place before the
+ * program starts up worker threads. This is currently used to assure
+ * that an nl_handle is allocated prior to any attempts to bind a
+ * netlink socket. For a discussion of why this is necessary, please
+ * see the following email message:
+ *
+ *   https://www.redhat.com/archives/libvir-list/2012-May/msg00202.html
+ *
+ * The short version is that, without this placeholder allocation of
+ * an nl_handle that is never used, it is possible for nl_connect() in
+ * one thread to collide with a direct bind() of a netlink socket in
+ * another thread, leading to failure of the operation (which could
+ * lead to failure of libvirtd to start). Since getaddrinfo() (used by
+ * libvirtd in virSocketAddrParse, which is called quite frequently
+ * during startup) directly calls bind() on a netlink socket, this is
+ * actually a very common occurrence (15-20% failure rate on some
+ * hardware).
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int
+virNetlinkStartup(void)
+{
+    if (placeholder_nlhandle)
+        return 0;
+    placeholder_nlhandle = nl_handle_alloc();
+    if (!placeholder_nlhandle) {
+        virReportSystemError(errno, "%s",
+                             _("cannot allocate placeholder nlhandle for netlink"));
+        return -1;
+    }
+    return 0;
+}
+
+/**
+ * virNetlinkShutdown:
+ *
+ * Undo any initialization done by virNetlinkStartup. This currently
+ * destroys the placeholder nl_handle.
+ */
+void
+virNetlinkShutdown(void)
+{
+    if (placeholder_nlhandle) {
+        nl_handle_destroy(placeholder_nlhandle);
+        placeholder_nlhandle = NULL;
+    }
+}
+
 /**
  * virNetlinkCommand:
  * @nlmsg: pointer to netlink message
@@ -536,6 +589,18 @@ static const char *unsupported = N_("libnl was not available at build time");
 static const char *unsupported = N_("not supported on non-linux platforms");
 # endif
 
+int
+virNetlinkStartup(void)
+{
+    return 0;
+}
+
+void
+virNetlinkShutdown(void)
+{
+    return;
+}
+
 int virNetlinkCommand(struct nl_msg *nl_msg ATTRIBUTE_UNUSED,
            unsigned char **respbuf ATTRIBUTE_UNUSED,
            unsigned int *respbuflen ATTRIBUTE_UNUSED,
index a72612e4a86d880d986ff6cc7b16cce9750a9841..93df59ad821aba81d315d0cead6673f1cce5035e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010-2012 Red Hat, Inc.
  * Copyright (C) 2010-2012 IBM Corporation
  *
  * This library is free software; you can redistribute it and/or
@@ -35,6 +35,9 @@ struct nlattr;
 
 # endif /* __linux__ */
 
+int virNetlinkStartup(void);
+void virNetlinkShutdown(void);
+
 int virNetlinkCommand(struct nl_msg *nl_msg,
                       unsigned char **respbuf, unsigned int *respbuflen,
                       int nl_pid);