[libvirt] [PATCH 1/6] Refactor job statistics

John Ferlan jferlan at redhat.com
Fri Sep 5 18:41:21 UTC 2014



On 09/01/2014 11:05 AM, Jiri Denemark wrote:
> Job statistics data were tracked in several structures and variables.
> Let's make a new qemuDomainJobInfo structure which can be used as a
> single source of statistics data as a preparation for storing data about
> completed a job.
> 
> Signed-off-by: Jiri Denemark <jdenemar at redhat.com>
> ---
>  src/qemu/qemu_domain.c    | 157 ++++++++++++++++++++++++++++++++++++++++++++--
>  src/qemu/qemu_domain.h    |  24 ++++++-
>  src/qemu/qemu_driver.c    | 119 ++++-------------------------------
>  src/qemu/qemu_migration.c |  72 ++++++++-------------
>  4 files changed, 213 insertions(+), 159 deletions(-)
> 

Curious why the decision to use "Ptr" instead of inline struct for
current & completed?  When I saw an alloc in the middle of a structure
and then a few free's along the way I began to wonder and attempt to
research the various paths to make sure all accesses knew/checked that
the impending deref would be OK - I marked those I found... I think one
or two may need double check since I assume you know the overall code
paths better. I see there's a path from qemuProcessReconnect() - that's
the libvirtd restart path right? So when the VIR_ALLOC() is done for
current/completed - who's address space is that? Wouldn't that be
address space from the "old" libvirtd?

Maybe I'm overthinking it on a Friday :-)

> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index e9506e0..2c709e9 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -163,11 +163,9 @@ qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv)
>      job->asyncOwner = 0;
>      job->phase = 0;
>      job->mask = DEFAULT_JOB_MASK;
> -    job->start = 0;
>      job->dump_memory_only = false;
>      job->asyncAbort = false;
> -    memset(&job->status, 0, sizeof(job->status));
> -    memset(&job->info, 0, sizeof(job->info));
> +    VIR_FREE(job->current);

This was one of those free paths where there were multiple callers and I
wasn't 100% other accesses needed to be checked w/r/t to this occurring
before an unchecked access in some other path...

>  }
>  
>  void
> @@ -200,6 +198,7 @@ qemuDomainObjTransferJob(virDomainObjPtr obj)
>  static void
>  qemuDomainObjFreeJob(qemuDomainObjPrivatePtr priv)
>  {
> +    VIR_FREE(priv->job.current);
>      virCondDestroy(&priv->job.cond);
>      virCondDestroy(&priv->job.asyncCond);
>  }
> @@ -211,6 +210,150 @@ qemuDomainTrackJob(qemuDomainJob job)
>  }
>  
>  
> +int
> +qemuDomainJobInfoUpdateTime(qemuDomainJobInfoPtr jobInfo)
> +{
> +    unsigned long long now;
> +
> +    if (!jobInfo->started)
> +        return 0;

any chance jobInfo == NULL?  I think the only path where the caller
doesn't check for current (or completed) is qemuMigrationUpdateJobStatus

> +
> +    if (virTimeMillisNow(&now) < 0)
> +        return -1;
> +
> +    jobInfo->timeElapsed = now - jobInfo->started;
> +    return 0;
> +}
> +
> +int
> +qemuDomainJobInfoToInfo(qemuDomainJobInfoPtr jobInfo,
> +                        virDomainJobInfoPtr info)
> +{

Called with job.current checked

> +    info->timeElapsed = jobInfo->timeElapsed;
> +    info->timeRemaining = jobInfo->timeRemaining;
> +
> +    info->memTotal = jobInfo->status.ram_total;
> +    info->memRemaining = jobInfo->status.ram_remaining;
> +    info->memProcessed = jobInfo->status.ram_transferred;
> +
> +    info->fileTotal = jobInfo->status.disk_total;
> +    info->fileRemaining = jobInfo->status.disk_remaining;
> +    info->fileProcessed = jobInfo->status.disk_transferred;
> +
> +    info->dataTotal = info->memTotal + info->fileTotal;
> +    info->dataRemaining = info->memRemaining + info->fileRemaining;
> +    info->dataProcessed = info->memProcessed + info->fileProcessed;
> +
> +    return 0;
> +}
> +
> +int
> +qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
> +                          int *type,
> +                          virTypedParameterPtr *params,
> +                          int *nparams)
> +{

Called with job.current (and .completed) checked...

> +    qemuMonitorMigrationStatus *status = &jobInfo->status;
> +    virTypedParameterPtr par = NULL;
> +    int maxpar = 0;
> +    int npar = 0;
> +
> +    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_TIME_ELAPSED,
> +                                jobInfo->timeElapsed) < 0)
> +        goto error;
> +
> +    if (jobInfo->type == VIR_DOMAIN_JOB_BOUNDED &&
> +        virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_TIME_REMAINING,
> +                                jobInfo->timeRemaining) < 0)
> +        goto error;
> +
> +    if (status->downtime_set &&
> +        virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_DOWNTIME,
> +                                status->downtime) < 0)
> +        goto error;
> +
> +    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_DATA_TOTAL,
> +                                status->ram_total +
> +                                status->disk_total) < 0 ||
> +        virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_DATA_PROCESSED,
> +                                status->ram_transferred +
> +                                status->disk_transferred) < 0 ||
> +        virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_DATA_REMAINING,
> +                                status->ram_remaining +
> +                                status->disk_remaining) < 0)
> +        goto error;
> +
> +    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_MEMORY_TOTAL,
> +                                status->ram_total) < 0 ||
> +        virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_MEMORY_PROCESSED,
> +                                status->ram_transferred) < 0 ||
> +        virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_MEMORY_REMAINING,
> +                                status->ram_remaining) < 0)
> +        goto error;
> +
> +    if (status->ram_duplicate_set) {
> +        if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                    VIR_DOMAIN_JOB_MEMORY_CONSTANT,
> +                                    status->ram_duplicate) < 0 ||
> +            virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                    VIR_DOMAIN_JOB_MEMORY_NORMAL,
> +                                    status->ram_normal) < 0 ||
> +            virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                    VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
> +                                    status->ram_normal_bytes) < 0)

I have a note in patch 2 about ram_normal and ram_normal_bytes vis-a-vis
qemu_monitor_json.c not checking status on their fetch and my latest
coverity run complaining about it.

> +            goto error;
> +    }
> +
> +    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_DISK_TOTAL,
> +                                status->disk_total) < 0 ||
> +        virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_DISK_PROCESSED,
> +                                status->disk_transferred) < 0 ||
> +        virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                VIR_DOMAIN_JOB_DISK_REMAINING,
> +                                status->disk_remaining) < 0)
> +        goto error;
> +
> +    if (status->xbzrle_set) {
> +        if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                    VIR_DOMAIN_JOB_COMPRESSION_CACHE,
> +                                    status->xbzrle_cache_size) < 0 ||
> +            virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                    VIR_DOMAIN_JOB_COMPRESSION_BYTES,
> +                                    status->xbzrle_bytes) < 0 ||
> +            virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                    VIR_DOMAIN_JOB_COMPRESSION_PAGES,
> +                                    status->xbzrle_pages) < 0 ||
> +            virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                    VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
> +                                    status->xbzrle_cache_miss) < 0 ||
> +            virTypedParamsAddULLong(&par, &npar, &maxpar,
> +                                    VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
> +                                    status->xbzrle_overflow) < 0)
> +            goto error;
> +    }
> +
> +    *type = jobInfo->type;
> +    *params = par;
> +    *nparams = npar;
> +    return 0;
> +
> + error:
> +    virTypedParamsFree(par, npar);
> +    return -1;
> +}
> +
> +
>  static void *
>  qemuDomainObjPrivateAlloc(void)
>  {
> @@ -1071,7 +1214,7 @@ qemuDomainObjBeginJobInternal(virQEMUDriverPtr driver,
>      unsigned long long then;
>      bool nested = job == QEMU_JOB_ASYNC_NESTED;
>      virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> -    int ret;
> +    int ret = -1;
>  
>      VIR_DEBUG("Starting %s: %s (async=%s vm=%p name=%s)",
>                job == QEMU_JOB_ASYNC ? "async job" : "job",

Just a note after this there's a

    priv->jobs_queued++;

which can be decremented at cleanup; however, if virTimeMillisNow()
fails, then there's a return -1 *and* a virObjectUnref(obj) before the
virObjectRef(obj)...


> @@ -1127,9 +1270,11 @@ qemuDomainObjBeginJobInternal(virQEMUDriverPtr driver,
>                    qemuDomainAsyncJobTypeToString(asyncJob),
>                    obj, obj->def->name);
>          qemuDomainObjResetAsyncJob(priv);
> +        if (VIR_ALLOC(priv->job.current) < 0)
> +            goto cleanup;

If this fails - what are the chances some other path will check/access
current without checking for it being NULL?  Perhaps low and there's
going to be other problems anyway in a low memory situation...

>          priv->job.asyncJob = asyncJob;
>          priv->job.asyncOwner = virThreadSelfID();
> -        priv->job.start = now;
> +        priv->job.current->started = now;
>      }
>  
>      if (qemuDomainTrackJob(job))
> @@ -1163,6 +1308,8 @@ qemuDomainObjBeginJobInternal(virQEMUDriverPtr driver,
>          virReportSystemError(errno,
>                               "%s", _("cannot acquire job mutex"));
>      }
> +
> + cleanup:
>      priv->jobs_queued--;
>      virObjectUnref(obj);
>      virObjectUnref(cfg);
> diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
> index 8736889..119590e 100644
> --- a/src/qemu/qemu_domain.h
> +++ b/src/qemu/qemu_domain.h
> @@ -100,6 +100,18 @@ typedef enum {
>  } qemuDomainAsyncJob;
>  VIR_ENUM_DECL(qemuDomainAsyncJob)
>  
> +typedef struct _qemuDomainJobInfo qemuDomainJobInfo;
> +typedef qemuDomainJobInfo *qemuDomainJobInfoPtr;
> +struct _qemuDomainJobInfo {
> +    virDomainJobType type;
> +    unsigned long long started; /* When the async job started */
> +    /* Computed values */
> +    unsigned long long timeElapsed;
> +    unsigned long long timeRemaining;
> +    /* Raw values from QEMU */
> +    qemuMonitorMigrationStatus status;
> +};
> +
>  struct qemuDomainJobObj {
>      virCond cond;                       /* Use to coordinate jobs */
>      qemuDomainJob active;               /* Currently running job */
> @@ -110,10 +122,8 @@ struct qemuDomainJobObj {
>      unsigned long long asyncOwner;      /* Thread which set current async job */
>      int phase;                          /* Job phase (mainly for migrations) */
>      unsigned long long mask;            /* Jobs allowed during async job */
> -    unsigned long long start;           /* When the async job started */
>      bool dump_memory_only;              /* use dump-guest-memory to do dump */
> -    qemuMonitorMigrationStatus status;  /* Raw async job progress data */
> -    virDomainJobInfo info;              /* Processed async job progress data */
> +    qemuDomainJobInfoPtr current;       /* async job progress data */
>      bool asyncAbort;                    /* abort of async job requested */
>  };
>  
> @@ -378,4 +388,12 @@ bool qemuDomainDefCheckABIStability(virQEMUDriverPtr driver,
>  bool qemuDomainAgentAvailable(qemuDomainObjPrivatePtr priv,
>                                bool reportError);
>  
> +int qemuDomainJobInfoUpdateTime(qemuDomainJobInfoPtr jobInfo);
> +int qemuDomainJobInfoToInfo(qemuDomainJobInfoPtr jobInfo,
> +                            virDomainJobInfoPtr info);
> +int qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
> +                              int *type,
> +                              virTypedParameterPtr *params,
> +                              int *nparams);
> +

Should any of these new defs need to have/use the ATTRIBUTE_NONNULL()
for params?

>  #endif /* __QEMU_DOMAIN_H__ */
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 239a300..265315d 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -2655,15 +2655,13 @@ qemuDomainGetControlInfo(virDomainPtr dom,
>      if (priv->monError) {
>          info->state = VIR_DOMAIN_CONTROL_ERROR;
>      } else if (priv->job.active) {
> -        if (!priv->monStart) {
> +        if (virTimeMillisNow(&info->stateTime) < 0)
> +            goto cleanup;
> +        if (priv->job.current) {
>              info->state = VIR_DOMAIN_CONTROL_JOB;
> -            if (virTimeMillisNow(&info->stateTime) < 0)
> -                goto cleanup;
> -            info->stateTime -= priv->job.start;
> +            info->stateTime -= priv->job.current->started;
>          } else {
>              info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
> -            if (virTimeMillisNow(&info->stateTime) < 0)
> -                goto cleanup;
>              info->stateTime -= priv->monStart;
>          }
>      } else {
> @@ -3110,8 +3108,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
>          goto endjob;
>      }
>  
> -    memset(&priv->job.info, 0, sizeof(priv->job.info));
> -    priv->job.info.type = VIR_DOMAIN_JOB_UNBOUNDED;
> +    priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;

Assumes current-> exists, but occurs after BeginAsyncJob() is
successful, so it seems safe.

>  
>      /* Pause */
>      if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
> @@ -3460,6 +3457,7 @@ static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
>                                            fd) < 0)
>          return -1;
>  
> +    VIR_FREE(priv->job.current);
>      priv->job.dump_memory_only = true;
>  
>      if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
> @@ -11616,17 +11614,15 @@ static int qemuDomainGetJobInfo(virDomainPtr dom,
>          goto cleanup;
>  
>      if (virDomainObjIsActive(vm)) {
> -        if (priv->job.asyncJob && !priv->job.dump_memory_only) {
> -            memcpy(info, &priv->job.info, sizeof(*info));
> -
> +        if (priv->job.current) {

Here there is a check for job.current before usage

>              /* Refresh elapsed time again just to ensure it
>               * is fully updated. This is primarily for benefit
>               * of incoming migration which we don't currently
>               * monitor actively in the background thread
>               */
> -            if (virTimeMillisNow(&info->timeElapsed) < 0)
> +            if (qemuDomainJobInfoUpdateTime(priv->job.current) < 0 ||
> +                qemuDomainJobInfoToInfo(priv->job.current, info) < 0)
>                  goto cleanup;
> -            info->timeElapsed -= priv->job.start;
>          } else {
>              memset(info, 0, sizeof(*info));
>              info->type = VIR_DOMAIN_JOB_NONE;
> @@ -11655,9 +11651,6 @@ qemuDomainGetJobStats(virDomainPtr dom,
>  {
>      virDomainObjPtr vm;
>      qemuDomainObjPrivatePtr priv;
> -    virTypedParameterPtr par = NULL;
> -    int maxpar = 0;
> -    int npar = 0;
>      int ret = -1;
>  
>      virCheckFlags(0, -1);
> @@ -11676,7 +11669,7 @@ qemuDomainGetJobStats(virDomainPtr dom,
>          goto cleanup;
>      }
>  
> -    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
> +    if (!priv->job.current) {
>          *type = VIR_DOMAIN_JOB_NONE;
>          *params = NULL;
>          *nparams = 0;

Here there is a check for job.current before usage below

> @@ -11689,102 +11682,16 @@ qemuDomainGetJobStats(virDomainPtr dom,
>       * of incoming migration which we don't currently
>       * monitor actively in the background thread
>       */
> -    if (virTimeMillisNow(&priv->job.info.timeElapsed) < 0)
> +    if (qemuDomainJobInfoUpdateTime(priv->job.current) < 0 ||
> +        qemuDomainJobInfoToParams(priv->job.current,
> +                                  type, params, nparams) < 0)
>          goto cleanup;
> -    priv->job.info.timeElapsed -= priv->job.start;
>  
> -    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_TIME_ELAPSED,
> -                                priv->job.info.timeElapsed) < 0)
> -        goto cleanup;
> -
> -    if (priv->job.info.type == VIR_DOMAIN_JOB_BOUNDED &&
> -        virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_TIME_REMAINING,
> -                                priv->job.info.timeRemaining) < 0)
> -        goto cleanup;
> -
> -    if (priv->job.status.downtime_set &&
> -        virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_DOWNTIME,
> -                                priv->job.status.downtime) < 0)
> -        goto cleanup;
> -
> -    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_DATA_TOTAL,
> -                                priv->job.info.dataTotal) < 0 ||
> -        virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_DATA_PROCESSED,
> -                                priv->job.info.dataProcessed) < 0 ||
> -        virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_DATA_REMAINING,
> -                                priv->job.info.dataRemaining) < 0)
> -        goto cleanup;
> -
> -    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_MEMORY_TOTAL,
> -                                priv->job.info.memTotal) < 0 ||
> -        virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_MEMORY_PROCESSED,
> -                                priv->job.info.memProcessed) < 0 ||
> -        virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_MEMORY_REMAINING,
> -                                priv->job.info.memRemaining) < 0)
> -        goto cleanup;
> -
> -    if (priv->job.status.ram_duplicate_set) {
> -        if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                    VIR_DOMAIN_JOB_MEMORY_CONSTANT,
> -                                    priv->job.status.ram_duplicate) < 0 ||
> -            virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                    VIR_DOMAIN_JOB_MEMORY_NORMAL,
> -                                    priv->job.status.ram_normal) < 0 ||
> -            virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                    VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
> -                                    priv->job.status.ram_normal_bytes) < 0)
> -            goto cleanup;
> -    }
> -
> -    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_DISK_TOTAL,
> -                                priv->job.info.fileTotal) < 0 ||
> -        virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_DISK_PROCESSED,
> -                                priv->job.info.fileProcessed) < 0 ||
> -        virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                VIR_DOMAIN_JOB_DISK_REMAINING,
> -                                priv->job.info.fileRemaining) < 0)
> -        goto cleanup;
> -
> -    if (priv->job.status.xbzrle_set) {
> -        if (virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                    VIR_DOMAIN_JOB_COMPRESSION_CACHE,
> -                                    priv->job.status.xbzrle_cache_size) < 0 ||
> -            virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                    VIR_DOMAIN_JOB_COMPRESSION_BYTES,
> -                                    priv->job.status.xbzrle_bytes) < 0 ||
> -            virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                    VIR_DOMAIN_JOB_COMPRESSION_PAGES,
> -                                    priv->job.status.xbzrle_pages) < 0 ||
> -            virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                    VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
> -                                    priv->job.status.xbzrle_cache_miss) < 0 ||
> -            virTypedParamsAddULLong(&par, &npar, &maxpar,
> -                                    VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
> -                                    priv->job.status.xbzrle_overflow) < 0)
> -            goto cleanup;
> -    }
> -
> -    *type = priv->job.info.type;
> -    *params = par;
> -    *nparams = npar;
>      ret = 0;
>  
>   cleanup:
>      if (vm)
>          virObjectUnlock(vm);
> -    if (ret < 0)
> -        virTypedParamsFree(par, npar);
>      return ret;
>  }
>  
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index 9cfb77e..64adab4 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -1723,8 +1723,9 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
>                               qemuDomainAsyncJob asyncJob)
>  {
>      qemuDomainObjPrivatePtr priv = vm->privateData;
> -    int ret;
>      qemuMonitorMigrationStatus status;
> +    qemuDomainJobInfoPtr jobInfo;
> +    int ret;
>  
>      memset(&status, 0, sizeof(status));
>  
> @@ -1738,62 +1739,40 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
>  
>      qemuDomainObjExitMonitor(driver, vm);
>  
> -    priv->job.status = status;
> -
> -    if (ret < 0 || virTimeMillisNow(&priv->job.info.timeElapsed) < 0)
> +    if (ret < 0 ||
> +        qemuDomainJobInfoUpdateTime(priv->job.current) < 0)

Here (and below) it's assumed job.current is valid.

>          return -1;
>  
> -    priv->job.info.timeElapsed -= priv->job.start;
> -
>      ret = -1;
> -    switch (priv->job.status.status) {
> -    case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
> -        priv->job.info.type = VIR_DOMAIN_JOB_NONE;
> -        virReportError(VIR_ERR_OPERATION_FAILED,
> -                       _("%s: %s"), job, _("is not active"));
> -        break;
> -
> +    jobInfo = priv->job.current;
> +    switch (status.status) {
> +    case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
> +        jobInfo->type = VIR_DOMAIN_JOB_COMPLETED;
> +        /* fall through */
>      case QEMU_MONITOR_MIGRATION_STATUS_SETUP:
> -        ret = 0;
> -        break;
> -
>      case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
> -        priv->job.info.fileTotal = priv->job.status.disk_total;
> -        priv->job.info.fileRemaining = priv->job.status.disk_remaining;
> -        priv->job.info.fileProcessed = priv->job.status.disk_transferred;
> -
> -        priv->job.info.memTotal = priv->job.status.ram_total;
> -        priv->job.info.memRemaining = priv->job.status.ram_remaining;
> -        priv->job.info.memProcessed = priv->job.status.ram_transferred;
> -
> -        priv->job.info.dataTotal =
> -            priv->job.status.ram_total + priv->job.status.disk_total;
> -        priv->job.info.dataRemaining =
> -            priv->job.status.ram_remaining + priv->job.status.disk_remaining;
> -        priv->job.info.dataProcessed =
> -            priv->job.status.ram_transferred +
> -            priv->job.status.disk_transferred;
> -
>          ret = 0;
>          break;
>  
> -    case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
> -        priv->job.info.type = VIR_DOMAIN_JOB_COMPLETED;
> -        ret = 0;
> +    case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
> +        jobInfo->type = VIR_DOMAIN_JOB_NONE;
> +        virReportError(VIR_ERR_OPERATION_FAILED,
> +                       _("%s: %s"), job, _("is not active"));
>          break;
>  
>      case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
> -        priv->job.info.type = VIR_DOMAIN_JOB_FAILED;
> +        jobInfo->type = VIR_DOMAIN_JOB_FAILED;
>          virReportError(VIR_ERR_OPERATION_FAILED,
>                         _("%s: %s"), job, _("unexpectedly failed"));
>          break;
>  
>      case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
> -        priv->job.info.type = VIR_DOMAIN_JOB_CANCELLED;
> +        jobInfo->type = VIR_DOMAIN_JOB_CANCELLED;
>          virReportError(VIR_ERR_OPERATION_ABORTED,
>                         _("%s: %s"), job, _("canceled by client"));
>          break;
>      }
> +    jobInfo->status = status;
>  
>      return ret;
>  }
> @@ -1803,11 +1782,14 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
>   * QEMU reports failed migration.
>   */
>  static int
> -qemuMigrationWaitForCompletion(virQEMUDriverPtr driver, virDomainObjPtr vm,
> +qemuMigrationWaitForCompletion(virQEMUDriverPtr driver,
> +                               virDomainObjPtr vm,
>                                 qemuDomainAsyncJob asyncJob,
> -                               virConnectPtr dconn, bool abort_on_error)
> +                               virConnectPtr dconn,
> +                               bool abort_on_error)
>  {
>      qemuDomainObjPrivatePtr priv = vm->privateData;
> +    qemuDomainJobInfoPtr jobInfo = priv->job.current;

Hopefully nothing has cleared or could clear this before this point...

>      const char *job;
>      int pauseReason;
>  
> @@ -1825,9 +1807,9 @@ qemuMigrationWaitForCompletion(virQEMUDriverPtr driver, virDomainObjPtr vm,
>          job = _("job");
>      }
>  
> -    priv->job.info.type = VIR_DOMAIN_JOB_UNBOUNDED;
> +    jobInfo->type = VIR_DOMAIN_JOB_UNBOUNDED;
>  
> -    while (priv->job.info.type == VIR_DOMAIN_JOB_UNBOUNDED) {
> +    while (jobInfo->type == VIR_DOMAIN_JOB_UNBOUNDED) {
>          /* Poll every 50ms for progress & to allow cancellation */
>          struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
>  
> @@ -1856,13 +1838,13 @@ qemuMigrationWaitForCompletion(virQEMUDriverPtr driver, virDomainObjPtr vm,
>          virObjectLock(vm);
>      }
>  
> -    if (priv->job.info.type == VIR_DOMAIN_JOB_COMPLETED) {
> +    if (jobInfo->type == VIR_DOMAIN_JOB_COMPLETED) {
>          return 0;
> -    } else if (priv->job.info.type == VIR_DOMAIN_JOB_UNBOUNDED) {
> +    } else if (jobInfo->type == VIR_DOMAIN_JOB_UNBOUNDED) {
>          /* The migration was aborted by us rather than QEMU itself so let's
>           * update the job type and notify the caller to send migrate_cancel.
>           */
> -        priv->job.info.type = VIR_DOMAIN_JOB_FAILED;
> +        jobInfo->type = VIR_DOMAIN_JOB_FAILED;
>          return -2;
>      } else {
>          return -1;
> @@ -4912,7 +4894,7 @@ qemuMigrationJobStart(virQEMUDriverPtr driver,
>                                       JOB_MASK(QEMU_JOB_MIGRATION_OP));
>      }
>  
> -    priv->job.info.type = VIR_DOMAIN_JOB_UNBOUNDED;
> +    priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;

This assumption of current-> should be OK since a failure from
qemuDomainObjBeginAsyncJob() wouldn't go through here.

>  
>      return 0;
>  }
> 

In general - I'm AOK with the code - my main concern has to do with
alloc'd memory...

John




More information about the libvir-list mailing list