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/nodedev/driver.pid
In unprivileged libvirtd this ends up locking
/run/user/$UID/libvirt/nodedev/run/driver.pid
NB, the latter can vary depending on $XDG_RUNTIME_DIR
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
src/conf/virnodedeviceobj.h | 5 +++++
src/node_device/node_device_hal.c | 31 +++++++++++++++++++++++++++++
src/node_device/node_device_udev.c | 32 ++++++++++++++++++++++++++++++
3 files changed, 68 insertions(+)
diff --git a/src/conf/virnodedeviceobj.h b/src/conf/virnodedeviceobj.h
index 1abfcb9af4..c4d3c55d73 100644
--- a/src/conf/virnodedeviceobj.h
+++ b/src/conf/virnodedeviceobj.h
@@ -37,6 +37,11 @@ typedef virNodeDeviceDriverState *virNodeDeviceDriverStatePtr;
struct _virNodeDeviceDriverState {
virMutex lock;
+ /* pid file FD, ensures two copies of the driver can't use the same root */
+ int lockFD;
+
+ char *stateDir;
+
virNodeDeviceObjListPtr devs; /* currently-known devices */
void *privateData; /* driver-specific private data */
bool privileged; /* whether we run in privileged mode */
diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c
index d1eb6c7851..876e808dce 100644
--- a/src/node_device/node_device_hal.c
+++ b/src/node_device/node_device_hal.c
@@ -33,10 +33,13 @@
#include "viralloc.h"
#include "viruuid.h"
#include "virpci.h"
+#include "virpidfile.h"
#include "virlog.h"
#include "virdbus.h"
#include "virstring.h"
+#include "configmake.h"
+
#define VIR_FROM_THIS VIR_FROM_NODEDEV
VIR_LOG_INIT("node_device.node_device_hal");
@@ -606,12 +609,36 @@ nodeStateInitialize(bool privileged ATTRIBUTE_UNUSED,
if (VIR_ALLOC(driver) < 0)
return -1;
+ driver->lockFD = -1;
if (virMutexInit(&driver->lock) < 0) {
VIR_FREE(driver);
return -1;
}
nodeDeviceLock();
+ if (privileged) {
+ if (virAsprintf(&driver->stateDir,
+ "%s/run/libvirt/nodedev", LOCALSTATEDIR) < 0)
+ goto failure;
+ } else {
+ VIR_AUTOFREE(char *) rundir = NULL;
+
+ if (!(rundir = virGetUserRuntimeDirectory()))
+ goto failure;
+ if (virAsprintf(&driver->stateDir, "%s/nodedev/run", rundir)
< 0)
+ goto failure;
+ }
+
+ if (virFileMakePathWithMode(driver->stateDir, S_IRWXU) < 0) {
+ virReportSystemError(errno, _("cannot create state directory
'%s'"),
+ driver->stateDir);
+ goto failure;
+ }
+
+ if ((driver->lockFD =
+ virPidFileAcquire(driver->stateDir, "driver", true, getpid())) <
0)
+ goto failure;
+
if (!(driver->devs = virNodeDeviceObjListNew()))
goto failure;
@@ -708,6 +735,10 @@ nodeStateCleanup(void)
virNodeDeviceObjListFree(driver->devs);
(void)libhal_ctx_shutdown(hal_ctx, NULL);
(void)libhal_ctx_free(hal_ctx);
+ if (driver->lockFD != -1)
+ virPidFileRelease(driver->stateDir, "driver",
driver->lockFD);
+
+ VIR_FREE(driver->stateDir);
nodeDeviceUnlock();
virMutexDestroy(&driver->lock);
VIR_FREE(driver);
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index 276bf3dd99..d883462948 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -38,10 +38,13 @@
#include "virbuffer.h"
#include "virfile.h"
#include "virpci.h"
+#include "virpidfile.h"
#include "virstring.h"
#include "virnetdev.h"
#include "virmdev.h"
+#include "configmake.h"
+
#define VIR_FROM_THIS VIR_FROM_NODEDEV
VIR_LOG_INIT("node_device.node_device_udev");
@@ -1494,6 +1497,11 @@ nodeStateCleanup(void)
virObjectUnref(driver->nodeDeviceEventState);
virNodeDeviceObjListFree(driver->devs);
+
+ if (driver->lockFD != -1)
+ virPidFileRelease(driver->stateDir, "driver", driver->lockFD);
+
+ VIR_FREE(driver->stateDir);
virMutexDestroy(&driver->lock);
VIR_FREE(driver);
@@ -1810,6 +1818,7 @@ nodeStateInitialize(bool privileged,
if (VIR_ALLOC(driver) < 0)
return -1;
+ driver->lockFD = -1;
if (virMutexInit(&driver->lock) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to initialize mutex"));
@@ -1819,6 +1828,29 @@ nodeStateInitialize(bool privileged,
driver->privileged = privileged;
+ 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;
+
if (!(driver->devs = virNodeDeviceObjListNew()) ||
!(priv = udevEventDataNew()))
goto cleanup;
--
2.21.0