[libvirt] [v2 RESEND 2/3] qemu: Introduce APIs for manipulating qemuDomainAgentJob

Jiri Denemark jdenemar at redhat.com
Tue Jun 19 11:50:27 UTC 2018


On Tue, Jun 19, 2018 at 08:38:01 +0200, Michal Privoznik wrote:
> The point is to break QEMU_JOB_* into smaller pieces which
> enables us to achieve higher throughput. For instance, if there
> are two threads, one is trying to query something on qemu
> monitor while the other is trying to query something on agent
> monitor these two threads would serialize. There is not much
> reason for that.
> 
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
>  src/qemu/THREADS.txt   | 112 ++++++++++++++++++++++++++---
>  src/qemu/qemu_domain.c | 187 +++++++++++++++++++++++++++++++++++++++----------
>  src/qemu/qemu_domain.h |  12 ++++
>  3 files changed, 264 insertions(+), 47 deletions(-)
...
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 91f3c6d236..30a06a1575 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
...
> @@ -6356,6 +6369,15 @@ qemuDomainJobAllowed(qemuDomainObjPrivatePtr priv, qemuDomainJob job)
>      return !priv->job.active && qemuDomainNestedJobAllowed(priv, job);
>  }
>  
> +static bool
> +qemuDomainObjCanSetJob(qemuDomainObjPrivatePtr priv,
> +                       qemuDomainJob job,
> +                       qemuDomainAgentJob agentJob)
> +{
> +    return (job == QEMU_JOB_NONE || !priv->job.active) &&
> +           (agentJob == QEMU_AGENT_JOB_NONE || !priv->job.agentActive);

This is pretty strange, everything you compare here is an enum, either
qemuDomainJob or qemuDomainAgentJob and mixing ! with an explicit
comparison with *_NONE is confusing. It's not incorrect, but I think

    (job == QEMU_JOB_NONE || priv->job.active == QEMU_JOB_NONE) &&
    (agentJob == QEMU_AGENT_JOB_NONE || priv->job.agentActive == QEMU_AGENT_JOB_NONE)

would be easier to read. Or alternatively you could use ! everywhere.

> +}
> +
>  /* Give up waiting for mutex after 30 seconds */
>  #define QEMU_JOB_WAIT_TIME (1000ull * 30)
>  
...
> @@ -6434,10 +6456,9 @@ qemuDomainObjBeginJobInternal(virQEMUDriverPtr driver,
>              goto error;
>      }
>  
> -    while (priv->job.active) {
> +    while (!qemuDomainObjCanSetJob(priv, job, agentJob)) {

You're now checking more variables for a single condition which means
waking up a single thread with virCondSignal could easily wake the one
which cannot currently run. We need to use virCondBroadcast instead and
I see you did the change, which is nice. However, it might be useful to
add a comment to the code explaining why we use virCondBroadcast to
avoid any future confusion or even blind attempts to replace it with
virCondSignal.

>          if (nowait)
>              goto cleanup;
> -

Drop this line removal, it's most likely a rebase artifact anyway.

>          VIR_DEBUG("Waiting for job (vm=%p name=%s)", obj, obj->def->name);
>          if (virCondWaitUntil(&priv->job.cond, &obj->parent.lock, then) < 0)
>              goto error;
> @@ -6448,32 +6469,48 @@ qemuDomainObjBeginJobInternal(virQEMUDriverPtr driver,
>      if (!nested && !qemuDomainNestedJobAllowed(priv, job))
>          goto retry;
>  
> -    qemuDomainObjResetJob(priv);
> -
>      ignore_value(virTimeMillisNow(&now));
>  
> -    if (job != QEMU_JOB_ASYNC) {
> -        VIR_DEBUG("Started job: %s (async=%s vm=%p name=%s)",
> -                   qemuDomainJobTypeToString(job),
> -                  qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
> -                  obj, obj->def->name);
> -        priv->job.active = job;
> -        priv->job.owner = virThreadSelfID();
> -        priv->job.ownerAPI = virThreadJobGet();
> +    if (job) {
> +        qemuDomainObjResetJob(priv);
> +
> +        if (job != QEMU_JOB_ASYNC) {
> +            VIR_DEBUG("Started job: %s (async=%s vm=%p name=%s)",
> +                      qemuDomainJobTypeToString(job),
> +                      qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
> +                      obj, obj->def->name);
> +            priv->job.active = job;
> +            priv->job.owner = virThreadSelfID();
> +            priv->job.ownerAPI = virThreadJobGet();
> +            priv->job.started = now;
> +        } else {
> +            VIR_DEBUG("Started async job: %s (vm=%p name=%s)",
> +                      qemuDomainAsyncJobTypeToString(asyncJob),
> +                      obj, obj->def->name);
> +            qemuDomainObjResetAsyncJob(priv);
> +            if (VIR_ALLOC(priv->job.current) < 0)
> +                goto cleanup;
> +            priv->job.current->status = QEMU_DOMAIN_JOB_STATUS_ACTIVE;
> +            priv->job.asyncJob = asyncJob;
> +            priv->job.asyncOwner = virThreadSelfID();
> +            priv->job.asyncOwnerAPI = virThreadJobGet();
> +            priv->job.asyncStarted = now;
> +            priv->job.current->started = now;
> +        }
> +    }
> +
> +    if (agentJob) {
> +        qemuDomainObjResetAgentJob(priv);
> +
> +        VIR_DEBUG("Started agent job: %s (vm=%p name=%s job=%s async=%s)",
> +                  qemuDomainAgentJobTypeToString(agentJob),
> +                  obj, obj->def->name,
> +                  qemuDomainJobTypeToString(priv->job.active),
> +                  qemuDomainAsyncJobTypeToString(priv->job.asyncJob));
> +        priv->job.agentActive = agentJob;
> +        priv->job.agentOwner = virThreadSelfID();
> +        priv->job.agentOwnerAPI = virThreadJobGet();
>          priv->job.started = now;

This should be priv->job.agentStarted = now

> -    } else {
> -        VIR_DEBUG("Started async job: %s (vm=%p name=%s)",
> -                  qemuDomainAsyncJobTypeToString(asyncJob),
> -                  obj, obj->def->name);
> -        qemuDomainObjResetAsyncJob(priv);
> -        if (VIR_ALLOC(priv->job.current) < 0)
> -            goto cleanup;
> -        priv->job.current->status = QEMU_DOMAIN_JOB_STATUS_ACTIVE;
> -        priv->job.asyncJob = asyncJob;
> -        priv->job.asyncOwner = virThreadSelfID();
> -        priv->job.asyncOwnerAPI = virThreadJobGet();
> -        priv->job.asyncStarted = now;
> -        priv->job.current->started = now;
>      }
>  
>      if (qemuDomainTrackJob(job))
> @@ -6554,12 +6591,46 @@ int qemuDomainObjBeginJob(virQEMUDriverPtr driver,
>                            qemuDomainJob job)
>  {
>      if (qemuDomainObjBeginJobInternal(driver, obj, job,
> +                                      QEMU_AGENT_JOB_NONE,
>                                        QEMU_ASYNC_JOB_NONE, false) < 0)
>          return -1;
>      else
>          return 0;
>  }
>  
> +/**
> + * qemuDomainObjBeginAgentJob:
> + *
> + * Grabs agent type of job. Use if caller talks to guest agent only.
> + *
> + * To end job call qemuDomainObjEndAgentJob.
> + */
> +int qemuDomainObjBeginAgentJob(virQEMUDriverPtr driver,
> +                               virDomainObjPtr obj,
> +                               qemuDomainAgentJob agentJob)

I know this file is pretty inconsistent and you're not making it a lot
worse, but s/int /int
/ and reindent the rest.

> +{
> +    return qemuDomainObjBeginJobInternal(driver, obj, QEMU_JOB_NONE,
> +                                         agentJob,
> +                                         QEMU_ASYNC_JOB_NONE, false);
> +}
> +
> +/**
> + * qemuDomainObjBeginJobWithAgent:
> + *
> + * Grabs both monitor and agent types of job. Use if caller talks to both
> + * monitor and guest agent.
> + *
> + * To end job call qemuDomainObjEndJobWithAgent.
> + */
> +int qemuDomainObjBeginJobWithAgent(virQEMUDriverPtr driver,
> +                                   virDomainObjPtr obj,
> +                                   qemuDomainJob job,
> +                                   qemuDomainAgentJob agentJob)

s/int /int
/ again

> +{
> +    return qemuDomainObjBeginJobInternal(driver, obj, job,
> +                                        agentJob, QEMU_ASYNC_JOB_NONE, false);

Strange indentation. And since you're going to touch the code here, the
following formatting would look a bit better:

    return qemuDomainObjBeginJobInternal(driver, obj, job, agentJob,
                                         QEMU_ASYNC_JOB_NONE, false);


> +}
> +
>  int qemuDomainObjBeginAsyncJob(virQEMUDriverPtr driver,
>                                 virDomainObjPtr obj,
>                                 qemuDomainAsyncJob asyncJob,
> @@ -6569,6 +6640,7 @@ int qemuDomainObjBeginAsyncJob(virQEMUDriverPtr driver,
>      qemuDomainObjPrivatePtr priv;
>  
>      if (qemuDomainObjBeginJobInternal(driver, obj, QEMU_JOB_ASYNC,
> +                                      QEMU_AGENT_JOB_NONE,
>                                        asyncJob, false) < 0)
>          return -1;
>  
> @@ -6598,6 +6670,7 @@ qemuDomainObjBeginNestedJob(virQEMUDriverPtr driver,
>  
>      return qemuDomainObjBeginJobInternal(driver, obj,
>                                           QEMU_JOB_ASYNC_NESTED,
> +                                         QEMU_AGENT_JOB_NONE,
>                                           QEMU_ASYNC_JOB_NONE,
>                                           false);
>  }
> @@ -6621,6 +6694,7 @@ qemuDomainObjBeginJobNowait(virQEMUDriverPtr driver,
>                              qemuDomainJob job)
>  {
>      return qemuDomainObjBeginJobInternal(driver, obj, job,
> +                                         QEMU_AGENT_JOB_NONE,
>                                           QEMU_ASYNC_JOB_NONE, true);
>  }
>  
> @@ -6646,7 +6720,47 @@ qemuDomainObjEndJob(virQEMUDriverPtr driver, virDomainObjPtr obj)
>      qemuDomainObjResetJob(priv);
>      if (qemuDomainTrackJob(job))
>          qemuDomainObjSaveJob(driver, obj);
> -    virCondSignal(&priv->job.cond);
> +    virCondBroadcast(&priv->job.cond);
> +}
> +
> +void
> +qemuDomainObjEndAgentJob(virDomainObjPtr obj)
> +{
> +    qemuDomainObjPrivatePtr priv = obj->privateData;
> +    qemuDomainAgentJob agentJob = priv->job.agentActive;
> +
> +    priv->jobs_queued--;
> +
> +    VIR_DEBUG("Stopping agent job: %s (async=%s vm=%p name=%s)",
> +              qemuDomainAgentJobTypeToString(agentJob),
> +              qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
> +              obj, obj->def->name);
> +
> +    qemuDomainObjResetAgentJob(priv);
> +    virCondBroadcast(&priv->job.cond);
> +}
> +
> +void
> +qemuDomainObjEndJobWithAgent(virQEMUDriverPtr driver,
> +                             virDomainObjPtr obj)
> +{
> +    qemuDomainObjPrivatePtr priv = obj->privateData;
> +    qemuDomainJob job = priv->job.active;
> +    qemuDomainAgentJob agentJob = priv->job.agentActive;
> +
> +    priv->jobs_queued--;
> +
> +    VIR_DEBUG("Stopping both jobs: %s %s (async=%s vm=%p name=%s)",
> +              qemuDomainJobTypeToString(job),
> +              qemuDomainAgentJobTypeToString(agentJob),
> +              qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
> +              obj, obj->def->name);
> +
> +    qemuDomainObjResetJob(priv);
> +    qemuDomainObjResetAgentJob(priv);
> +    if (qemuDomainTrackJob(job))
> +        qemuDomainObjSaveJob(driver, obj);
> +    virCondBroadcast(&priv->job.cond);
>  }
>  
>  void
> @@ -6800,8 +6914,9 @@ qemuDomainObjEnterMonitorAsync(virQEMUDriverPtr driver,
>   * obj must be locked before calling
>   *
>   * To be called immediately before any QEMU agent API call.
> - * Must have already called qemuDomainObjBeginJob() and checked
> - * that the VM is still active.
> + * Must have already called qemuDomainObjBeginAgentJob() or
> + * qemuDomainObjBeginJobWithAgent() and checked that the VM is
> + * still active.

The documentation of qemuDomainObjEnterMonitorInternal would benefit
from similar treatment.

>   *
>   * To be followed with qemuDomainObjExitAgent() once complete
>   */
...

With the small issues fixed

Reviewed-by: Jiri Denemark <jdenemar at redhat.com>




More information about the libvir-list mailing list