On 08/27/2018 04:08 AM, Michal Privoznik wrote:
> This flag causes connection to be opened when needed (e.g. when
> calling virLockManagerLockDaemonAcquire for the first time) and
> instead of closing it at the end of such API store it in
> privateData so that it can be reused by later calls.
>
> This is needed because if a resource is acquired and connection
> is closed then virtlockd kills the registered PID (that's what
> virtlockd is designed to do). Therefore we will need the
> connection to open at drvAcquire and close not any sooner than
> drvRelease. However, as we will be locking files step-by-step we
> want to avoid opening new connection for every drvAcquire +
> drvRelease pair, so the connection is going to be shared even
> more than that. But more on that in next commit.
>
> Signed-off-by: Michal Privoznik <mpriv...@redhat.com>
> ---
> src/locking/lock_driver.h | 7 +++++
> src/locking/lock_driver_lockd.c | 68
> +++++++++++++++++++++++++++++++++++++----
> 2 files changed, 69 insertions(+), 6 deletions(-)
>
> diff --git a/src/locking/lock_driver.h b/src/locking/lock_driver.h
> index 59c4c3aac7..7e3ffc58b5 100644
> --- a/src/locking/lock_driver.h
> +++ b/src/locking/lock_driver.h
> @@ -67,8 +67,15 @@ 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),
> + /* Causes driver to keep connection open and reuse it for further use. */
> + VIR_LOCK_MANAGER_ACQUIRE_KEEP_OPEN = (1 << 2),
> } virLockManagerAcquireFlags;
>
> +typedef enum {
> + /* Reuse previously saved connection. */
> + VIR_LOCK_MANAGER_RELEASE_KEEP_OPEN = (1 << 0),
> +} virLockManagerReleaseFlags;
> +
> typedef enum {
> /* virLockManagerNew called for a freshly started domain */
> VIR_LOCK_MANAGER_NEW_STARTED = (1 << 0),
> diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c
> index 4883e89ac6..14f9eae760 100644
> --- a/src/locking/lock_driver_lockd.c
> +++ b/src/locking/lock_driver_lockd.c
> @@ -76,6 +76,11 @@ struct _virLockManagerLockDaemonPrivate {
>
> size_t nresources;
> virLockManagerLockDaemonResourcePtr resources;
> +
> + int clientRefs;
> + virNetClientPtr client;
> + virNetClientProgramPtr program;
> + int counter;
> };
>
>
> @@ -440,6 +445,13 @@
> virLockManagerLockDaemonPrivateFree(virLockManagerLockDaemonPrivatePtr priv)
> default:
> break;
> }
> +
> + if (priv->client) {
> + virNetClientClose(priv->client);
> + virObjectUnref(priv->client);
> + virObjectUnref(priv->program);
> + }
> +
How about a helper method that would do these?
I wonder now if the @priv should keep track of flags as well?
That way you could "always" use @priv to store the client, program, and
counter and then use helper methods to determine at close whether @flags
had the KEEP_OPEN or not instead of having KEEP_OPEN in various places.
> VIR_FREE(priv);
> }
>
> @@ -770,7 +782,8 @@ static int
> virLockManagerLockDaemonAcquire(virLockManagerPtr lock,
> 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_KEEP_OPEN, -1);
>
> if (priv->type == VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN &&
> priv->nresources == 0 &&
> @@ -781,7 +794,14 @@ static int
> virLockManagerLockDaemonAcquire(virLockManagerPtr lock,
> return -1;
> }
>
> - if (!(client = virLockManagerLockDaemonConnect(lock, &program,
> &counter)))
> + if (flags & VIR_LOCK_MANAGER_ACQUIRE_KEEP_OPEN) {
> + client = priv->client;
> + program = priv->program;
> + counter = priv->counter;
> + }
> +
> + if (!client &&
> + !(client = virLockManagerLockDaemonConnect(lock, &program,
> &counter)))
If "always" storing in @priv this alters to if !priv->client &&
!(priv->client ==...
> goto cleanup;
>
> if (fd &&
> @@ -814,11 +834,25 @@ static int
> virLockManagerLockDaemonAcquire(virLockManagerPtr lock,
> virLockManagerLockDaemonConnectionRestrict(lock, client, program,
> &counter) < 0)
> goto cleanup;
>
> + if (flags & VIR_LOCK_MANAGER_ACQUIRE_KEEP_OPEN) {
> + VIR_STEAL_PTR(priv->client, client);
> + VIR_STEAL_PTR(priv->program, program);
> + priv->counter = counter;
> + }
> +
If "always" using @priv means this isn't necessary as long as @flags is
also stored.
> rv = 0;
>
> cleanup:
> - if (rv != 0 && fd)
> - VIR_FORCE_CLOSE(*fd);
> + if (rv < 0) {
> + if (fd)
> + VIR_FORCE_CLOSE(*fd);
> +
> + priv->client = NULL;
> + priv->program = NULL;
> + priv->counter = 0;
> + priv->clientRefs = 0;
So one failure this time causes previously stored successes to be thrown
away? Or am I reading too much into this? Why is clientRefs not
auto-incremented here, but auto-decremented in Release?
This is where I'd think a helper would be able to know the "last"
referenced was removed and thus be able to perform the close and free of
resources.
Calling *PrivateFree and finding that there's extra clientRefs
would/could mean something is programatically wrong, right?
> + }
> +
> virNetClientClose(client);
> virObjectUnref(client);
> virObjectUnref(program);
Always storing in @priv, priv->flags, and using @rv I would think could
easily be managed in a helper...
> @@ -837,12 +871,20 @@ static int
> virLockManagerLockDaemonRelease(virLockManagerPtr lock,
> size_t i;
> virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
>
> - virCheckFlags(0, -1);
> + virCheckFlags(VIR_LOCK_MANAGER_RELEASE_KEEP_OPEN, -1);
>
> if (state)
> *state = NULL;
>
> - if (!(client = virLockManagerLockDaemonConnect(lock, &program,
> &counter)))
> + if (flags & VIR_LOCK_MANAGER_RELEASE_KEEP_OPEN) {
> + client = priv->client;
> + program = priv->program;
> + counter = priv->counter;
> + priv->clientRefs--;
This decrements something from 0...
> + }
> +
> + if (!client &&
> + !(client = virLockManagerLockDaemonConnect(lock, &program,
> &counter)))
> goto cleanup;
>
> for (i = 0; i < priv->nresources; i++) {
> @@ -870,9 +912,23 @@ static int
> virLockManagerLockDaemonRelease(virLockManagerPtr lock,
> goto cleanup;
> }
>
> + if (flags & VIR_LOCK_MANAGER_RELEASE_KEEP_OPEN) {
> + /* Avoid freeing in cleanup. */
> + client = NULL;
> + program = NULL;
> + counter = 0;
> + }
> +
> rv = 0;
>
> cleanup:
> + if (rv < 0) {
> + priv->client = NULL;
> + priv->program = NULL;
> + priv->counter = 0;
> + priv->clientRefs = 0;
> + }
> +
Again, I'm not clear why when this release fails we go off and clear out
everything? Including things that may have been connected before?
Certain a properly documented helper would solve this mystery for me.
One that could manage things based on KEEP_OPEN, @priv, and @rv. I would
assume the close open when KEEP_OPEN is true would be where the
auto-decrement would occur and be checked to determine whether the
subsequent closes and unref's happen.
John
> virNetClientClose(client);
> virObjectUnref(client);
> virObjectUnref(program);
>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list