[libvirt] [PATCH 3/3] qemu: report block job errors from qemu to the user

Jiri Denemark jdenemar at redhat.com
Thu Oct 6 08:01:04 UTC 2016


On Wed, Oct 05, 2016 at 16:52:10 +0300, Nikolay Shirokovskiy wrote:
> ---
>  src/qemu/qemu_blockjob.c     | 13 +++++++++++--
>  src/qemu/qemu_blockjob.h     |  3 ++-
>  src/qemu/qemu_domain.h       |  1 +
>  src/qemu/qemu_driver.c       |  4 ++--
>  src/qemu/qemu_migration.c    | 34 ++++++++++++++++++++++------------
>  src/qemu/qemu_monitor.c      |  5 +++--
>  src/qemu/qemu_monitor.h      |  4 +++-
>  src/qemu/qemu_monitor_json.c |  2 +-
>  src/qemu/qemu_process.c      |  3 +++
>  9 files changed, 48 insertions(+), 21 deletions(-)
> 
> diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
> index 83a5a3f..937d931 100644
> --- a/src/qemu/qemu_blockjob.c
> +++ b/src/qemu/qemu_blockjob.c
> @@ -33,6 +33,7 @@
>  #include "virstoragefile.h"
>  #include "virthread.h"
>  #include "virtime.h"
> +#include "viralloc.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_QEMU
>  
> @@ -53,16 +54,24 @@ VIR_LOG_INIT("qemu.qemu_blockjob");
>  int
>  qemuBlockJobUpdate(virQEMUDriverPtr driver,
>                     virDomainObjPtr vm,
> -                   virDomainDiskDefPtr disk)
> +                   virDomainDiskDefPtr disk,
> +                   char **error)
>  {
>      qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
>      int status = diskPriv->blockJobStatus;
>  
> +    if (error)
> +        *error = NULL;
> +
>      if (status != -1) {
>          qemuBlockJobEventProcess(driver, vm, disk,
>                                   diskPriv->blockJobType,
>                                   diskPriv->blockJobStatus);
>          diskPriv->blockJobStatus = -1;
> +        if (error)
> +            VIR_STEAL_PTR(*error, diskPriv->blockJobHint);
> +        else
> +            VIR_FREE(diskPriv->blockJobHint);

What if qemuBlockJobUpdate is never called? Shouldn't
qemuBlockJobEventProcess be the place to free the error?

>      }
>  
>      return status;
> @@ -241,6 +250,6 @@ qemuBlockJobSyncEnd(virQEMUDriverPtr driver,
>                      virDomainDiskDefPtr disk)
>  {
>      VIR_DEBUG("disk=%s", disk->dst);
> -    qemuBlockJobUpdate(driver, vm, disk);
> +    qemuBlockJobUpdate(driver, vm, disk, NULL);
>      QEMU_DOMAIN_DISK_PRIVATE(disk)->blockJobSync = false;
>  }
> diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
> index 775ce95..c452edc 100644
> --- a/src/qemu/qemu_blockjob.h
> +++ b/src/qemu/qemu_blockjob.h
> @@ -27,7 +27,8 @@
>  
>  int qemuBlockJobUpdate(virQEMUDriverPtr driver,
>                         virDomainObjPtr vm,
> -                       virDomainDiskDefPtr disk);
> +                       virDomainDiskDefPtr disk,
> +                       char **error);
>  void qemuBlockJobEventProcess(virQEMUDriverPtr driver,
>                                virDomainObjPtr vm,
>                                virDomainDiskDefPtr disk,
> diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
> index 521531b..79d88fa 100644
> --- a/src/qemu/qemu_domain.h
> +++ b/src/qemu/qemu_domain.h
> @@ -290,6 +290,7 @@ struct _qemuDomainDiskPrivate {
>      /* for some synchronous block jobs, we need to notify the owner */
>      int blockJobType;   /* type of the block job from the event */
>      int blockJobStatus; /* status of the finished block job */
> +    char *blockJobHint; /* hint from block job event (like error message) */

So why is this called blockJobHint if it's used for storing the errors?
I think blockJobError would be a better name...

And you forgot to free it in qemuDomainDiskPrivateDispose.

>      bool blockJobSync; /* the block job needs synchronized termination */
>  
>      bool migrating; /* the disk is being migrated */
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index ee16cb5..ac204c3 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -16280,13 +16280,13 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
>                                       VIR_DOMAIN_BLOCK_JOB_CANCELED);
>          } else {
>              qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
> -            qemuBlockJobUpdate(driver, vm, disk);
> +            qemuBlockJobUpdate(driver, vm, disk, NULL);
>              while (diskPriv->blockjob) {
>                  if (virDomainObjWait(vm) < 0) {
>                      ret = -1;
>                      goto endjob;
>                  }
> -                qemuBlockJobUpdate(driver, vm, disk);
> +                qemuBlockJobUpdate(driver, vm, disk, NULL);
>              }
>          }
>      }
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index 8a220d9..0671e23 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -1853,17 +1853,20 @@ qemuMigrationDriveMirrorReady(virQEMUDriverPtr driver,
>      for (i = 0; i < vm->def->ndisks; i++) {
>          virDomainDiskDefPtr disk = vm->def->disks[i];
>          qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
> +        char *error;
>  
>          if (!diskPriv->migrating)
>              continue;
>  
> -        status = qemuBlockJobUpdate(driver, vm, disk);
> +        status = qemuBlockJobUpdate(driver, vm, disk, &error);
>          if (status == VIR_DOMAIN_BLOCK_JOB_FAILED) {
>              virReportError(VIR_ERR_OPERATION_FAILED,
> -                           _("migration of disk %s failed"),
> -                           disk->dst);
> +                           _("migration of disk %s failed: %s"),
> +                           disk->dst, NULLSTR(error));

I think we'll need two error messages depending on whether error is
NULL. Reporting "migration of disk vda failed: <null>" is not a good
idea.

> +            VIR_FREE(error);
>              return -1;
>          }
> +        VIR_FREE(error);
>  
>          if (disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_READY)
>              notReady++;
> @@ -1902,17 +1905,18 @@ qemuMigrationDriveMirrorCancelled(virQEMUDriverPtr driver,
>      for (i = 0; i < vm->def->ndisks; i++) {
>          virDomainDiskDefPtr disk = vm->def->disks[i];
>          qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
> +        char *error;
>  
>          if (!diskPriv->migrating)
>              continue;
>  
> -        status = qemuBlockJobUpdate(driver, vm, disk);
> +        status = qemuBlockJobUpdate(driver, vm, disk, &error);
>          switch (status) {
>          case VIR_DOMAIN_BLOCK_JOB_FAILED:
>              if (check) {
>                  virReportError(VIR_ERR_OPERATION_FAILED,
> -                               _("migration of disk %s failed"),
> -                               disk->dst);
> +                               _("migration of disk %s failed: %s"),
> +                               disk->dst, NULLSTR(error));

Ditto.

>                  failed = true;
>              }
>              /* fallthrough */
> @@ -1925,6 +1929,7 @@ qemuMigrationDriveMirrorCancelled(virQEMUDriverPtr driver,
>          default:
>              active++;
>          }
> +        VIR_FREE(error);
>      }
>  
>      if (failed) {
> @@ -1962,24 +1967,28 @@ qemuMigrationCancelOneDriveMirror(virQEMUDriverPtr driver,
>  {
>      qemuDomainObjPrivatePtr priv = vm->privateData;
>      char *diskAlias = NULL;
> +    char *error;
>      int ret = -1;
>      int status;
>      int rv;
>  
> -    status = qemuBlockJobUpdate(driver, vm, disk);
> +    status = qemuBlockJobUpdate(driver, vm, disk, &error);
>      switch (status) {
>      case VIR_DOMAIN_BLOCK_JOB_FAILED:
>      case VIR_DOMAIN_BLOCK_JOB_CANCELED:
>          if (failNoJob) {
>              virReportError(VIR_ERR_OPERATION_FAILED,
> -                           _("migration of disk %s failed"),
> -                           disk->dst);
> -            return -1;
> +                           _("migration of disk %s failed: %s"),
> +                           disk->dst, NULLSTR(error));

Ditto.

> +            ret = -1;

No need to set ret = -1.

> +            goto cleanup;
>          }
> -        return 1;
> +        ret = 1;
> +        goto cleanup;

I think we should just let it fall through to the next case...

>  
>      case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
> -        return 1;
> +        ret = 1;
> +        goto cleanup;
>      }
>  
>      if (!(diskAlias = qemuAliasFromDisk(disk)))
> @@ -1997,6 +2006,7 @@ qemuMigrationCancelOneDriveMirror(virQEMUDriverPtr driver,
>  
>   cleanup:
>      VIR_FREE(diskAlias);
> +    VIR_FREE(error);
>      return ret;
>  }
>
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 8083a36..3466225 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -1458,13 +1458,14 @@ int
>  qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
>                          const char *diskAlias,
>                          int type,
> -                        int status)
> +                        int status,
> +                        const char *hint)

s/hint/error/ here and in the rest of the patch.

Jirka




More information about the libvir-list mailing list