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

Reply via email to