[...]
VIR_FROM_THIS VIR_FROM_SECURITY
VIR_LOG_INIT("security.security_manager");
+virMutex lockManagerMutex = VIR_MUTEX_INITIALIZER;
+
struct _virSecurityManager {
virObjectLockable parent;
@@ -43,6 +47,7 @@ struct _virSecurityManager {
void *privateData;
virLockManagerPluginPtr lockPlugin;
+ int fd;
};
static virClassPtr virSecurityManagerClass;
@@ -57,6 +62,7 @@ void virSecurityManagerDispose(void *obj)
mgr->drv->close(mgr);
virObjectUnref(mgr->lockPlugin);
+ VIR_FORCE_CLOSE(mgr->fd);
VIR_FREE(mgr->privateData);
}
@@ -109,6 +115,7 @@ virSecurityManagerNewDriver(virSecurityDriverPtr drv,
mgr->flags = flags;
mgr->virtDriver = virtDriver;
VIR_STEAL_PTR(mgr->privateData, privateData);
+ mgr->fd = -1;
if (drv->open(mgr) < 0)
goto error;
@@ -1263,3 +1270,131 @@ virSecurityManagerRestoreTPMLabels(virSecurityManagerPtr mgr,
return 0;
}
+
+
+static virLockManagerPtr
+virSecurityManagerNewLockManager(virSecurityManagerPtr mgr,
+ const char * const *paths,
+ size_t npaths)
+{
+ virLockManagerPtr lock;
+ virLockManagerParam params[] = {
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_UUID,
+ .key = "uuid",
+ },
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_STRING,
+ .key = "name",
+ .value = { .cstr = "libvirtd-sec" },
+ },
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
+ .key = "pid",
+ .value = { .iv = getpid() },
+ },
+ };
+ const unsigned int flags = 0;
+ size_t i;
+
+ if (virGetHostUUID(params[0].value.uuid) < 0)
+ return NULL;
+
+ if (!(lock = virLockManagerNew(virLockManagerPluginGetDriver(mgr->lockPlugin),
+ VIR_LOCK_MANAGER_OBJECT_TYPE_DAEMON,
+ ARRAY_CARDINALITY(params),
+ params,
+ flags)))
+ return NULL;
+
+ for (i = 0; i < npaths; i++) {
+ if (virLockManagerAddResource(lock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_METADATA,
+ paths[i], 0, NULL, 0) < 0)
+ goto error;
+ }
+
+ return lock;
+ error:
+ virLockManagerFree(lock);
+ return NULL;
+}
+
+
+/* How many seconds should we try to acquire the lock before
+ * giving up. */
+#define LOCK_ACQUIRE_TIMEOUT 60
+
+int
+virSecurityManagerMetadataLock(virSecurityManagerPtr mgr,
+ const char * const *paths,
+ size_t npaths)
+{
+ virLockManagerPtr lock;
+ virTimeBackOffVar timebackoff;
+ int fd = -1;
+ int rv;
+ int ret = -1;
+
+ virMutexLock(&lockManagerMutex);
+
+ if (!(lock = virSecurityManagerNewLockManager(mgr, paths, npaths)))
+ goto cleanup;
+
After seeing it in use in patch 19 and thinking about it for a very
short period of time, would it make more sense to store @lock somewhere
so that virSecurityManagerMetadataUnlock doesn't fail because the
virSecurityManagerNewLockManager fails?
The @mgr is mutex locked so that nothing can change @mgr while this Meta
Lock/Unlock is occurring. It'd be a shame to not call
virLockManagerRelease just because we didn't save @lock
John
+ if (virTimeBackOffStart(&timebackoff, 1,
LOCK_ACQUIRE_TIMEOUT * 1000) < 0)
+ goto cleanup;
+ while (virTimeBackOffWait(&timebackoff)) {
+ rv = virLockManagerAcquire(lock, NULL,
+ VIR_LOCK_MANAGER_ACQUIRE_ROLLBACK,
+ VIR_DOMAIN_LOCK_FAILURE_DEFAULT, &fd);
+
+ if (rv >= 0)
+ break;
+
+ if (virGetLastErrorCode() == VIR_ERR_RESOURCE_BUSY)
+ continue;
+
+ goto cleanup;
+ }
+
+ if (rv < 0)
+ goto cleanup;
+
+ mgr->fd = fd;
+ fd = -1;
+
+ ret = 0;
+ cleanup:
+ virLockManagerFree(lock);
+ VIR_FORCE_CLOSE(fd);
+ if (ret < 0)
+ virMutexUnlock(&lockManagerMutex);
+ return ret;
+}
+
+
+int
+virSecurityManagerMetadataUnlock(virSecurityManagerPtr mgr,
+ const char * const *paths,
+ size_t npaths)
+{
+ virLockManagerPtr lock;
+ int fd;
+ int ret = -1;
+
+ /* lockManagerMutex acquired from previous
+ * virSecurityManagerMetadataLock() call. */
+
+ fd = mgr->fd;
+ mgr->fd = -1;
+
+ if (!(lock = virSecurityManagerNewLockManager(mgr, paths, npaths)))
+ goto cleanup;
+
+ if (virLockManagerRelease(lock, NULL, 0) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ virLockManagerFree(lock);
+ VIR_FORCE_CLOSE(fd);
+ virMutexUnlock(&lockManagerMutex);
+ return ret;
+}