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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list