--- src/qemu/qemu_blockjob.c | 13 +++++++++-- src/qemu/qemu_blockjob.h | 3 ++- src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 4 ++-- src/qemu/qemu_migration.c | 54 +++++++++++++++++++++++++++++++------------- src/qemu/qemu_monitor.c | 5 ++-- src/qemu/qemu_monitor.h | 4 +++- src/qemu/qemu_monitor_json.c | 4 +++- src/qemu/qemu_process.c | 4 ++++ 10 files changed, 68 insertions(+), 25 deletions(-) diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index 83a5a3f..30beeeb 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->blockJobError); + else + VIR_FREE(diskPriv->blockJobError); } 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.c b/src/qemu/qemu_domain.c index 0c9416f..307d83a 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -774,6 +774,7 @@ qemuDomainDiskPrivateDispose(void *obj) qemuDomainSecretInfoFree(&priv->secinfo); qemuDomainSecretInfoFree(&priv->encinfo); + VIR_FREE(priv->blockJobError); } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index dee5d93..c470cbf 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 *blockJobError; /* block job completed event error */ 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 8789c9d..bc7f840 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16326,13 +16326,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 1c4a80c..1762648 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1859,17 +1859,25 @@ 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); + if (error) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("migration of disk %s failed: %s"), + disk->dst, error); + VIR_FREE(error); + } else { + virReportError(VIR_ERR_OPERATION_FAILED, + _("migration of disk %s failed"), disk->dst); + } return -1; } + VIR_FREE(error); if (disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_READY) notReady++; @@ -1908,17 +1916,23 @@ 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); + if (error) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("migration of disk %s failed: %s"), + disk->dst, error); + } else { + virReportError(VIR_ERR_OPERATION_FAILED, + _("migration of disk %s failed"), disk->dst); + } failed = true; } /* fallthrough */ @@ -1931,6 +1945,7 @@ qemuMigrationDriveMirrorCancelled(virQEMUDriverPtr driver, default: active++; } + VIR_FREE(error); } if (failed) { @@ -1968,24 +1983,30 @@ 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; + if (error) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("migration of disk %s failed: %s"), + disk->dst, error); + } else { + virReportError(VIR_ERR_OPERATION_FAILED, + _("migration of disk %s failed"), disk->dst); + } + goto cleanup; } - return 1; - + /* fallthrough */ case VIR_DOMAIN_BLOCK_JOB_COMPLETED: - return 1; + ret = 1; + goto cleanup; } if (!(diskAlias = qemuAliasFromDisk(disk))) @@ -2003,6 +2024,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 5175f4e..34a393a 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 *error) { int ret = -1; VIR_DEBUG("mon=%p", mon); QEMU_MONITOR_CALLBACK(mon, ret, domainBlockJob, mon->vm, - diskAlias, type, status); + diskAlias, type, status, error); return ret; } diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 7d78e5b..522675f 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -146,6 +146,7 @@ typedef int (*qemuMonitorDomainBlockJobCallback)(qemuMonitorPtr mon, const char *diskAlias, int type, int status, + const char *error, void *opaque); typedef int (*qemuMonitorDomainTrayChangeCallback)(qemuMonitorPtr mon, virDomainObjPtr vm, @@ -332,7 +333,8 @@ int qemuMonitorEmitPMSuspend(qemuMonitorPtr mon); int qemuMonitorEmitBlockJob(qemuMonitorPtr mon, const char *diskAlias, int type, - int status); + int status, + const char *error); int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon, unsigned long long actual); int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index b93220b..271598f 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -802,6 +802,7 @@ qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon, { const char *device; const char *type_str; + const char *error = NULL; int type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN; unsigned long long offset, len; @@ -834,6 +835,7 @@ qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon, switch ((virConnectDomainEventBlockJobStatus) event) { case VIR_DOMAIN_BLOCK_JOB_COMPLETED: + error = virJSONValueObjectGetString(data, "error"); /* Make sure the whole device has been processed */ if (offset != len) event = VIR_DOMAIN_BLOCK_JOB_FAILED; @@ -848,7 +850,7 @@ qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon, } out: - qemuMonitorEmitBlockJob(mon, device, type, event); + qemuMonitorEmitBlockJob(mon, device, type, event, error); } static void diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 0f5a11b..e5390b4 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -975,6 +975,7 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *diskAlias, int type, int status, + const char *error, void *opaque) { virQEMUDriverPtr driver = opaque; @@ -996,6 +997,9 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED, /* We have a SYNC API waiting for this event, dispatch it back */ diskPriv->blockJobType = type; diskPriv->blockJobStatus = status; + VIR_FREE(diskPriv->blockJobError); + if (error && VIR_STRDUP_QUIET(diskPriv->blockJobError, error) < 0) + VIR_WARN("Can not pass error message further: %s", error); virDomainObjBroadcast(vm); } else { /* there is no waiting SYNC API, dispatch the update to a thread */ -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list