diff --git a/src/locking/lock_driver.h b/src/locking/lock_driver.h index 9be0abcfba4602b08e5ecfe2238e59efd5e43e8d..7c8f744be3baa38022856f6ea91ea6645389bddc 100644 --- a/src/locking/lock_driver.h +++ b/src/locking/lock_driver.h @@ -67,6 +67,10 @@ typedef enum { VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY = (1 << 0), /* Prevent further lock/unlock calls from this process */ VIR_LOCK_MANAGER_ACQUIRE_RESTRICT = (1 << 1), + /* Used when acquiring more resources in which one of them + * can't be acquired, perform a rollback and release all + * resources acquired so far. */ + VIR_LOCK_MANAGER_ACQUIRE_ROLLBACK = (1 << 2), } virLockManagerAcquireFlags; typedef enum { diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index d6551e125ca7c3e6a35e8bc997cf5f25f68c78be..85cdcf97be6fad76974cf0673d6ad8a0e8aa9c11 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -735,6 +735,34 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr lock, } +static int virLockManagerLockDaemonReleaseImpl(virNetClientPtr client, + virNetClientProgramPtr program, + int counter, + virLockManagerLockDaemonResourcePtr res) +{ + virLockSpaceProtocolReleaseResourceArgs args; + + memset(&args, 0, sizeof(args)); + + args.path = res->lockspace; + args.name = res->name; + args.flags = res->flags; + + args.flags &= + ~(VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED | + VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE | + VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_METADATA); + + return virNetClientProgramCall(program, + client, + counter, + VIR_LOCK_SPACE_PROTOCOL_PROC_RELEASE_RESOURCE, + 0, NULL, NULL, NULL, + (xdrproc_t)xdr_virLockSpaceProtocolReleaseResourceArgs, &args, + (xdrproc_t)xdr_void, NULL); +} + + static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock, const char *state ATTRIBUTE_UNUSED, unsigned int flags, @@ -745,10 +773,13 @@ static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock, virNetClientProgramPtr program = NULL; int counter = 0; int rv = -1; + ssize_t i; + ssize_t lastGood = -1; virLockManagerLockDaemonPrivatePtr priv = lock->privateData; virCheckFlags(VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY | - VIR_LOCK_MANAGER_ACQUIRE_RESTRICT, -1); + VIR_LOCK_MANAGER_ACQUIRE_RESTRICT | + VIR_LOCK_MANAGER_ACQUIRE_ROLLBACK, -1); if (priv->type == VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN && priv->nresources == 0 && @@ -767,7 +798,6 @@ static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock, goto cleanup; if (!(flags & VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY)) { - size_t i; for (i = 0; i < priv->nresources; i++) { virLockSpaceProtocolAcquireResourceArgs args; @@ -785,6 +815,7 @@ static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock, (xdrproc_t)xdr_virLockSpaceProtocolAcquireResourceArgs, &args, (xdrproc_t)xdr_void, NULL) < 0) goto cleanup; + lastGood = i; } } @@ -795,8 +826,28 @@ static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock, rv = 0; cleanup: - if (rv != 0 && fd) - VIR_FORCE_CLOSE(*fd); + if (rv < 0) { + int saved_errno = errno; + virErrorPtr origerr; + + virErrorPreserveLast(&origerr); + if (fd) + VIR_FORCE_CLOSE(*fd); + + if (flags & VIR_LOCK_MANAGER_ACQUIRE_ROLLBACK) { + for (i = lastGood; i >= 0; i--) { + virLockManagerLockDaemonResourcePtr res = &priv->resources[i]; + + if (virLockManagerLockDaemonReleaseImpl(client, program, + counter++, res) < 0) + VIR_WARN("Unable to release resource lockspace=%s name=%s", + res->lockspace, res->name); + } + } + + virErrorRestore(&origerr); + errno = saved_errno; + } virNetClientClose(client); virObjectUnref(client); virObjectUnref(program); @@ -824,27 +875,10 @@ static int virLockManagerLockDaemonRelease(virLockManagerPtr lock, goto cleanup; for (i = 0; i < priv->nresources; i++) { - virLockSpaceProtocolReleaseResourceArgs args; - - memset(&args, 0, sizeof(args)); + virLockManagerLockDaemonResourcePtr res = &priv->resources[i]; - if (priv->resources[i].lockspace) - args.path = priv->resources[i].lockspace; - args.name = priv->resources[i].name; - args.flags = priv->resources[i].flags; - - args.flags &= - ~(VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED | - VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE | - VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_METADATA); - - if (virNetClientProgramCall(program, - client, - counter++, - VIR_LOCK_SPACE_PROTOCOL_PROC_RELEASE_RESOURCE, - 0, NULL, NULL, NULL, - (xdrproc_t)xdr_virLockSpaceProtocolReleaseResourceArgs, &args, - (xdrproc_t)xdr_void, NULL) < 0) + if (virLockManagerLockDaemonReleaseImpl(client, program, + counter++, res) < 0) goto cleanup; }