[libvirt] [PATCHv2 2/4] network: change location of network state xml files

Laine Stump laine at laine.org
Thu Apr 17 11:43:20 UTC 2014


For some reason these have been stored in /var/lib, although other
drivers (e.g. qemu and lxc) store their state files in /var/run.

It's much nicer to store state files in /var/run because it is
automatically cleared out when the system reboots. We can then use
existence of the state file as a convenient indicator of whether or
not a particular network is active.

Since changing the location of the state files by itself will cause
problems in the case of a *live* upgrade from an older libvirt that
uses /var/lib (because current status of active networks will be
lost), the network driver initialization has been modified to migrate
any network state files from /var/lib to /var/run.

This will not help those trying to *downgrade*, but in practice this
will only be problematic in two cases

1) If there are networks with network-wide bandwidth limits configured
   *and in use* by a guest during a downgrade to "old" libvirt. In this
   case, the class ID's used for that network's tc rules, as well as
   the currently in-use bandwidth "floor" will be forgotten.

2) If someone does this: 1) upgrade libvirt, 2) downgrade libvirt, 3)
   modify running state of network (e.g. add a static dhcp host, etc),
   4) upgrade. In this case, the modifications to the running network
   will be lost (but not any persistent changes to the network's
   config).
---
change from V1:

* merged previous 2/5 & 3/5 into a single patch that changes the
  location and migrates old state files, to avoid potential problems
  by people trying to use git bisect.

* move the files with a direct copy, rather than reading/parsing the
  XML then formatting/writing it. Note (hopefully) correct use of
  readdir!

* put the migration into a separate static function

* don't put oldStateDir in driverState, as we only use it once during
  initialization.

* only attempt migration when running privileged, since the
  unprivileged state location hasn't changed.

 src/network/bridge_driver.c | 97 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 91 insertions(+), 6 deletions(-)

diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 4ca3de5..57dfb2d 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -41,6 +41,7 @@
 #include <sys/wait.h>
 #include <sys/ioctl.h>
 #include <net/if.h>
+#include <dirent.h>
 #if HAVE_SYS_SYSCTL_H
 # include <sys/sysctl.h>
 #endif
@@ -416,6 +417,88 @@ firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
 }
 #endif
 
+static int
+networkMigrateStateFiles(virNetworkDriverStatePtr driver)
+{
+    /* Due to a change in location of network state xml beginning in
+     * libvirt 1.2.4 (from /var/lib/libvirt/network to
+     * /var/run/libvirt/network), we must check for state files in two
+     * locations. Anything found in the old location must be written
+     * to the new location, then erased from the old location. (Note
+     * that we read/write the file rather than calling rename()
+     * because the old and new state directories are likely in
+     * different filesystems).
+     */
+    int ret = -1;
+    const char *oldStateDir = LOCALSTATEDIR "/lib/libvirt/network";
+    DIR *dir;
+    struct dirent *entry;
+    char *oldPath = NULL, *newPath = NULL;
+    char *contents = NULL;
+
+    if (!(dir = opendir(oldStateDir))) {
+        if (errno == ENOENT)
+            return 0;
+
+        virReportSystemError(errno, _("failed to open directory '%s'"),
+                             oldStateDir);
+        return -1;
+    }
+
+    if (virFileMakePath(driver->stateDir) < 0) {
+        virReportSystemError(errno, _("cannot create directory %s"),
+                             driver->stateDir);
+        goto cleanup;
+    }
+
+    for (;;) {
+        errno = 0;
+        entry = readdir(dir);
+        if (!entry) {
+            if (errno) {
+                virReportSystemError(errno, _("failed to read directory '%s'"),
+                                     oldStateDir);
+                goto cleanup;
+            }
+            break;
+        }
+
+        if (entry->d_type != DT_REG ||
+            STREQ(entry->d_name, ".") ||
+            STREQ(entry->d_name, ".."))
+            continue;
+
+        if (virAsprintf(&oldPath, "%s/%s",
+                        oldStateDir, entry->d_name) < 0)
+           goto cleanup;
+        if (virFileReadAll(oldPath, 1024*1024, &contents) < 0)
+           goto cleanup;
+
+        if (virAsprintf(&newPath, "%s/%s",
+                        driver->stateDir, entry->d_name) < 0)
+           goto cleanup;
+        if (virFileWriteStr(newPath, contents, S_IRUSR | S_IWUSR) < 0) {
+            virReportSystemError(errno,
+                                 _("failed to write network status file '%s'"),
+                                 newPath);
+            goto cleanup;
+        }
+
+        unlink(oldPath);
+        VIR_FREE(oldPath);
+        VIR_FREE(newPath);
+        VIR_FREE(contents);
+    }
+
+    ret = 0;
+ cleanup:
+    closedir(dir);
+    VIR_FREE(oldPath);
+    VIR_FREE(newPath);
+    VIR_FREE(contents);
+    return ret;
+}
+
 /**
  * networkStateInitialize:
  *
@@ -445,11 +528,6 @@ networkStateInitialize(bool privileged,
     /* configuration/state paths are one of
      * ~/.config/libvirt/... (session/unprivileged)
      * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
-     *
-     * NB: The qemu driver puts its domain state in /var/run, and I
-     * think the network driver should have used /var/run too (instead
-     * of /var/lib), but it's been this way for a long time, and we
-     * probably shouldn't change it now.
      */
     if (privileged) {
         if (VIR_STRDUP(driverState->networkConfigDir,
@@ -457,7 +535,7 @@ networkStateInitialize(bool privileged,
             VIR_STRDUP(driverState->networkAutostartDir,
                        SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
             VIR_STRDUP(driverState->stateDir,
-                       LOCALSTATEDIR "/lib/libvirt/network") < 0 ||
+                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
             VIR_STRDUP(driverState->pidDir,
                        LOCALSTATEDIR "/run/libvirt/network") < 0 ||
             VIR_STRDUP(driverState->dnsmasqStateDir,
@@ -465,6 +543,13 @@ networkStateInitialize(bool privileged,
             VIR_STRDUP(driverState->radvdStateDir,
                        LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
             goto error;
+
+        /* migration from old to new location is only applicable for
+         * privileged mode - unprivileged mode directories haven't
+         * changed location.
+         */
+        if (networkMigrateStateFiles(driverState) < 0)
+            goto error;
     } else {
         configdir = virGetUserConfigDirectory();
         rundir = virGetUserRuntimeDirectory();
-- 
1.9.0




More information about the libvir-list mailing list