When we allow multiple instances of the driver for the same user account, using a separate root directory, we need to ensure mutual exclusion. Use a pidfile to guarantee this.
In privileged libvirtd this ends up locking /var/run/libvirt/interface/driver.pid In unprivileged libvirtd this ends up locking /run/user/$UID/libvirt/interface/run/driver.pid NB, the latter can vary depending on $XDG_RUNTIME_DIR Signed-off-by: Daniel P. Berrangé <berra...@redhat.com> --- src/interface/interface_backend_netcf.c | 45 +++++++++++++++++++++++-- src/interface/interface_backend_udev.c | 44 +++++++++++++++++++++++- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/interface/interface_backend_netcf.c b/src/interface/interface_backend_netcf.c index cf8eb9488d..868e49c56e 100644 --- a/src/interface/interface_backend_netcf.c +++ b/src/interface/interface_backend_netcf.c @@ -29,10 +29,14 @@ #include "interface_conf.h" #include "viralloc.h" #include "virlog.h" +#include "virfile.h" +#include "virpidfile.h" #include "virstring.h" #include "viraccessapicheck.h" #include "virinterfaceobj.h" +#include "configmake.h" + #define VIR_FROM_THIS VIR_FROM_INTERFACE VIR_LOG_INIT("interface.interface_backend_netcf"); @@ -43,6 +47,10 @@ VIR_LOG_INIT("interface.interface_backend_netcf"); typedef struct { virObjectLockable parent; + /* pid file FD, ensures two copies of the driver can't use the same root */ + int lockFD; + + char *stateDir; struct netcf *netcf; bool privileged; } virNetcfDriverState, *virNetcfDriverStatePtr; @@ -71,6 +79,11 @@ virNetcfDriverStateDispose(void *obj) if (_driver->netcf) ncf_close(_driver->netcf); + + if (_driver->lockFD != -1) + virPidFileRelease(_driver->stateDir, "driver", _driver->lockFD); + + VIR_FREE(_driver->stateDir); } @@ -87,15 +100,41 @@ netcfStateInitialize(bool privileged, driver->privileged = privileged; + if (privileged) { + if (virAsprintf(&driver->stateDir, + "%s/run/libvirt/nodedev", LOCALSTATEDIR) < 0) + goto error; + } else { + VIR_AUTOFREE(char *) rundir = NULL; + + if (!(rundir = virGetUserRuntimeDirectory())) + goto error; + if (virAsprintf(&driver->stateDir, "%s/nodedev/run", rundir) < 0) + goto error; + } + + if (virFileMakePathWithMode(driver->stateDir, S_IRWXU) < 0) { + virReportSystemError(errno, _("cannot create state directory '%s'"), + driver->stateDir); + goto error; + } + + if ((driver->lockFD = + virPidFileAcquire(driver->stateDir, "driver", true, getpid())) < 0) + goto error; + /* open netcf */ if (ncf_init(&driver->netcf, NULL) != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to initialize netcf")); - virObjectUnref(driver); - driver = NULL; - return -1; + goto error; } return 0; + + error: + virObjectUnref(driver); + driver = NULL; + return -1; } diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index 1373356246..fcd7f1c04a 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -32,14 +32,21 @@ #include "interface_conf.h" #include "viralloc.h" #include "virstring.h" +#include "virpidfile.h" #include "viraccessapicheck.h" #include "virinterfaceobj.h" #include "virnetdev.h" +#include "configmake.h" + #define VIR_FROM_THIS VIR_FROM_INTERFACE struct udev_iface_driver { struct udev *udev; + /* pid file FD, ensures two copies of the driver can't use the same root */ + int lockFD; + + char *stateDir; bool privileged; }; @@ -1157,6 +1164,9 @@ udevInterfaceIsActive(virInterfacePtr ifinfo) } +static int +udevStateCleanup(void); + static int udevStateInitialize(bool privileged, virStateInhibitCallback callback ATTRIBUTE_UNUSED, @@ -1167,6 +1177,31 @@ udevStateInitialize(bool privileged, if (VIR_ALLOC(driver) < 0) goto cleanup; + driver->lockFD = -1; + + if (privileged) { + if (virAsprintf(&driver->stateDir, + "%s/run/libvirt/nodedev", LOCALSTATEDIR) < 0) + goto cleanup; + } else { + VIR_AUTOFREE(char *) rundir = NULL; + + if (!(rundir = virGetUserRuntimeDirectory())) + goto cleanup; + if (virAsprintf(&driver->stateDir, "%s/nodedev/run", rundir) < 0) + goto cleanup; + } + + if (virFileMakePathWithMode(driver->stateDir, S_IRWXU) < 0) { + virReportSystemError(errno, _("cannot create state directory '%s'"), + driver->stateDir); + goto cleanup; + } + + if ((driver->lockFD = + virPidFileAcquire(driver->stateDir, "driver", true, getpid())) < 0) + goto cleanup; + driver->udev = udev_new(); if (!driver->udev) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -1178,6 +1213,8 @@ udevStateInitialize(bool privileged, ret = 0; cleanup: + if (ret < 0) + udevStateCleanup(); return ret; } @@ -1187,8 +1224,13 @@ udevStateCleanup(void) if (!driver) return -1; - udev_unref(driver->udev); + if (driver->udev) + udev_unref(driver->udev); + + if (driver->lockFD != -1) + virPidFileRelease(driver->stateDir, "driver", driver->lockFD); + VIR_FREE(driver->stateDir); VIR_FREE(driver); return 0; } -- 2.21.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list