[libvirt] [PATCH v4 16/23] security_manager: Introduce metadata locking APIs
John Ferlan
jferlan at redhat.com
Mon Sep 17 22:12:26 UTC 2018
[...]
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;
> +}
More information about the libvir-list
mailing list