Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx> --- Notes: Version 2: - new patch src/conf/domain_conf.c | 6 ----- src/conf/domain_conf.h | 10 -------- src/libvirt_private.syms | 1 - src/qemu/qemu_blockjob.c | 48 +++++++++++++++++++++---------------- src/qemu/qemu_domain.c | 61 +++++++++++++++++++++++++++++++++++++++++++---- src/qemu/qemu_domain.h | 21 ++++++++++++++++ src/qemu/qemu_driver.c | 11 +++++---- src/qemu/qemu_migration.c | 6 +++-- src/qemu/qemu_process.c | 17 +++++++------ 9 files changed, 125 insertions(+), 56 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 3204140..bf0099d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1290,11 +1290,6 @@ virDomainDiskDefNew(virDomainXMLOptionPtr xmlopt) !(ret->privateData = xmlopt->privateData.diskNew())) goto error; - if (virCondInit(&ret->blockJobSyncCond) < 0) { - virReportSystemError(errno, "%s", _("Failed to initialize condition")); - goto error; - } - return ret; error: @@ -1319,7 +1314,6 @@ virDomainDiskDefFree(virDomainDiskDefPtr def) VIR_FREE(def->domain_name); virDomainDeviceInfoClear(&def->info); virObjectUnref(def->privateData); - virCondDestroy(&def->blockJobSyncCond); VIR_FREE(def); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index b5e7617..8312c20 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -691,20 +691,10 @@ struct _virDomainDiskDef { int tray_status; /* enum virDomainDiskTray */ int removable; /* enum virTristateSwitch */ - /* ideally we want a smarter way to interlock block jobs on single qemu disk - * in the future, but for now we just disallow any concurrent job on a - * single disk */ - bool blockjob; virStorageSourcePtr mirror; int mirrorState; /* enum virDomainDiskMirrorState */ int mirrorJob; /* virDomainBlockJobType */ - /* for some synchronous block jobs, we need to notify the owner */ - virCond blockJobSyncCond; - int blockJobType; /* type of the block job from the event */ - int blockJobStatus; /* status of the finished block job */ - bool blockJobSync; /* the block job needs synchronized termination */ - struct { unsigned int cylinders; unsigned int heads; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 67a7e21..2586572 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -308,7 +308,6 @@ virDomainGraphicsTypeFromString; virDomainGraphicsTypeToString; virDomainGraphicsVNCSharePolicyTypeFromString; virDomainGraphicsVNCSharePolicyTypeToString; -virDomainHasBlockjob; virDomainHasNet; virDomainHostdevCapsTypeToString; virDomainHostdevDefAlloc; diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index 729928a..b9572d0 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -65,6 +65,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virDomainDiskDefPtr persistDisk = NULL; bool save = false; + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); /* Have to generate two variants of the event for old vs. new * client callbacks */ @@ -127,7 +128,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN; ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk, true, true)); - disk->blockjob = false; + diskPriv->blockjob = false; break; case VIR_DOMAIN_BLOCK_JOB_READY: @@ -143,7 +144,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, VIR_DOMAIN_DISK_MIRROR_STATE_ABORT : VIR_DOMAIN_DISK_MIRROR_STATE_NONE; disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN; save = true; - disk->blockjob = false; + diskPriv->blockjob = false; break; case VIR_DOMAIN_BLOCK_JOB_LAST: @@ -185,11 +186,13 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, void qemuBlockJobSyncBegin(virDomainDiskDefPtr disk) { - if (disk->blockJobSync) + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + + if (diskPriv->blockJobSync) VIR_WARN("Disk %s already has synchronous block job", disk->dst); - disk->blockJobSync = true; + diskPriv->blockJobSync = true; } @@ -211,15 +214,17 @@ qemuBlockJobSyncEnd(virQEMUDriverPtr driver, virDomainDiskDefPtr disk, virConnectDomainEventBlockJobStatus *ret_status) { - if (disk->blockJobSync && disk->blockJobStatus != -1) { + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + + if (diskPriv->blockJobSync && diskPriv->blockJobStatus != -1) { if (ret_status) - *ret_status = disk->blockJobStatus; + *ret_status = diskPriv->blockJobStatus; qemuBlockJobEventProcess(driver, vm, disk, - disk->blockJobType, - disk->blockJobStatus); - disk->blockJobStatus = -1; + diskPriv->blockJobType, + diskPriv->blockJobStatus); + diskPriv->blockJobStatus = -1; } - disk->blockJobSync = false; + diskPriv->blockJobSync = false; } @@ -248,24 +253,26 @@ qemuBlockJobSyncWaitWithTimeout(virQEMUDriverPtr driver, unsigned long long timeout, virConnectDomainEventBlockJobStatus *ret_status) { - if (!disk->blockJobSync) { + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + + if (!diskPriv->blockJobSync) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("No current synchronous block job")); return -1; } - while (disk->blockJobSync && disk->blockJobStatus == -1) { + while (diskPriv->blockJobSync && diskPriv->blockJobStatus == -1) { int r; if (!virDomainObjIsActive(vm)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("guest unexpectedly quit")); - disk->blockJobSync = false; + diskPriv->blockJobSync = false; return -1; } if (timeout == (unsigned long long)-1) { - r = virCondWait(&disk->blockJobSyncCond, &vm->parent.lock); + r = virCondWait(&diskPriv->blockJobSyncCond, &vm->parent.lock); } else if (timeout) { unsigned long long now; if (virTimeMillisNow(&now) < 0) { @@ -273,7 +280,8 @@ qemuBlockJobSyncWaitWithTimeout(virQEMUDriverPtr driver, _("Unable to get current time")); return -1; } - r = virCondWaitUntil(&disk->blockJobSyncCond, &vm->parent.lock, + r = virCondWaitUntil(&diskPriv->blockJobSyncCond, + &vm->parent.lock, now + timeout); if (r < 0 && errno == ETIMEDOUT) return 0; @@ -283,7 +291,7 @@ qemuBlockJobSyncWaitWithTimeout(virQEMUDriverPtr driver, } if (r < 0) { - disk->blockJobSync = false; + diskPriv->blockJobSync = false; virReportSystemError(errno, "%s", _("Unable to wait on block job sync " "condition")); @@ -292,11 +300,11 @@ qemuBlockJobSyncWaitWithTimeout(virQEMUDriverPtr driver, } if (ret_status) - *ret_status = disk->blockJobStatus; + *ret_status = diskPriv->blockJobStatus; qemuBlockJobEventProcess(driver, vm, disk, - disk->blockJobType, - disk->blockJobStatus); - disk->blockJobStatus = -1; + diskPriv->blockJobType, + diskPriv->blockJobStatus); + diskPriv->blockJobStatus = -1; return 0; } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index b69f10f..608eed7 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -412,6 +412,53 @@ qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo, } +static virClassPtr qemuDomainDiskPrivateClass; +static void qemuDomainDiskPrivateDispose(void *obj); + +static int +qemuDomainDiskPrivateOnceInit(void) +{ + qemuDomainDiskPrivateClass = virClassNew(virClassForObject(), + "qemuDomainDiskPrivate", + sizeof(qemuDomainDiskPrivate), + qemuDomainDiskPrivateDispose); + if (!qemuDomainDiskPrivateClass) + return -1; + else + return 0; +} + +VIR_ONCE_GLOBAL_INIT(qemuDomainDiskPrivate) + +static virObjectPtr +qemuDomainDiskPrivateNew(void) +{ + qemuDomainDiskPrivatePtr priv; + + if (qemuDomainDiskPrivateInitialize() < 0) + return NULL; + + if (!(priv = virObjectNew(qemuDomainDiskPrivateClass))) + return NULL; + + if (virCondInit(&priv->blockJobSyncCond) < 0) { + virReportSystemError(errno, "%s", _("Failed to initialize condition")); + virObjectUnref(priv); + return NULL; + } + + return (virObjectPtr) priv; +} + +static void +qemuDomainDiskPrivateDispose(void *obj) +{ + qemuDomainDiskPrivatePtr priv = obj; + + virCondDestroy(&priv->blockJobSyncCond); +} + + static void * qemuDomainObjPrivateAlloc(void) { @@ -741,6 +788,7 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data) virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks = { .alloc = qemuDomainObjPrivateAlloc, .free = qemuDomainObjPrivateFree, + .diskNew = qemuDomainDiskPrivateNew, .parse = qemuDomainObjPrivateXMLParse, .format = qemuDomainObjPrivateXMLFormat, }; @@ -2809,6 +2857,8 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver, bool qemuDomainDiskBlockJobIsActive(virDomainDiskDefPtr disk) { + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + if (disk->mirror) { virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, _("disk '%s' already in active block job"), @@ -2817,7 +2867,7 @@ qemuDomainDiskBlockJobIsActive(virDomainDiskDefPtr disk) return true; } - if (disk->blockjob) { + if (diskPriv->blockjob) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("disk '%s' already in active block job"), disk->dst); @@ -2843,12 +2893,13 @@ qemuDomainHasBlockjob(virDomainObjPtr vm, { size_t i; for (i = 0; i < vm->def->ndisks; i++) { - if (!copy_only && - vm->def->disks[i]->blockjob) + virDomainDiskDefPtr disk = vm->def->disks[i]; + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + + if (!copy_only && diskPriv->blockjob) return true; - if (vm->def->disks[i]->mirror && - vm->def->disks[i]->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) + if (disk->mirror && disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) return true; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 7f2e4b5..53df1d3 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -34,6 +34,7 @@ # include "qemu_conf.h" # include "qemu_capabilities.h" # include "virchrdev.h" +# include "virobject.h" # define QEMU_DOMAIN_FORMAT_LIVE_FLAGS \ (VIR_DOMAIN_XML_SECURE | \ @@ -199,6 +200,26 @@ struct _qemuDomainObjPrivate { virBitmapPtr autoCpuset; }; +# define QEMU_DOMAIN_DISK_PRIVATE(disk) \ + ((qemuDomainDiskPrivatePtr) (disk)->privateData) + +typedef struct _qemuDomainDiskPrivate qemuDomainDiskPrivate; +typedef qemuDomainDiskPrivate *qemuDomainDiskPrivatePtr; +struct _qemuDomainDiskPrivate { + virObject parent; + + /* ideally we want a smarter way to interlock block jobs on single qemu disk + * in the future, but for now we just disallow any concurrent job on a + * single disk */ + bool blockjob; + + /* for some synchronous block jobs, we need to notify the owner */ + virCond blockJobSyncCond; + int blockJobType; /* type of the block job from the event */ + int blockJobStatus; /* status of the finished block job */ + bool blockJobSync; /* the block job needs synchronized termination */ +}; + typedef enum { QEMU_PROCESS_EVENT_WATCHDOG = 0, QEMU_PROCESS_EVENT_GUESTPANIC, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c54199c..9344533 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -14315,9 +14315,10 @@ qemuDomainSnapshotPrepare(virConnectPtr conn, for (i = 0; i < def->ndisks; i++) { virDomainSnapshotDiskDefPtr disk = &def->disks[i]; virDomainDiskDefPtr dom_disk = vm->def->disks[i]; + qemuDomainDiskPrivatePtr dom_diskPriv = QEMU_DOMAIN_DISK_PRIVATE(dom_disk); if (disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_NONE && - dom_disk->blockjob) { + dom_diskPriv->blockjob) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("disk '%s' has an active block job"), disk->name); @@ -16637,7 +16638,7 @@ qemuDomainBlockPullCommon(virQEMUDriverPtr driver, if (ret < 0) goto endjob; - disk->blockjob = true; + QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob = true; endjob: qemuDomainObjEndJob(driver, vm); @@ -16765,7 +16766,7 @@ qemuDomainBlockJobAbort(virDomainPtr dom, } endjob: - if (disk && disk->blockJobSync) + if (disk && QEMU_DOMAIN_DISK_PRIVATE(disk)->blockJobSync) qemuBlockJobSyncEnd(driver, vm, disk, NULL); qemuDomainObjEndJob(driver, vm); @@ -17098,7 +17099,7 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm, disk->mirror = mirror; mirror = NULL; disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY; - disk->blockjob = true; + QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob = true; if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) VIR_WARN("Unable to save status on vm %s after state change", @@ -17491,7 +17492,7 @@ qemuDomainBlockCommit(virDomainPtr dom, } if (ret == 0) - disk->blockjob = true; + QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob = true; if (mirror) { if (ret == 0) { diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 8f2189b..7472b09 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1743,6 +1743,7 @@ qemuMigrationCheckDriveMirror(virQEMUDriverPtr driver, for (i = 0; i < vm->def->ndisks; i++) { virDomainDiskDefPtr disk = vm->def->disks[i]; + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); /* skip shared, RO and source-less disks */ if (disk->src->shared || disk->src->readonly || @@ -1750,7 +1751,7 @@ qemuMigrationCheckDriveMirror(virQEMUDriverPtr driver, continue; /* skip disks that didn't start mirroring */ - if (!disk->blockJobSync) + if (!diskPriv->blockJobSync) continue; /* process any pending event */ @@ -1871,6 +1872,7 @@ qemuMigrationCancelDriveMirror(virQEMUDriverPtr driver, for (i = 0; i < vm->def->ndisks; i++) { virDomainDiskDefPtr disk = vm->def->disks[i]; + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); /* skip shared, RO and source-less disks */ if (disk->src->shared || disk->src->readonly || @@ -1878,7 +1880,7 @@ qemuMigrationCancelDriveMirror(virQEMUDriverPtr driver, continue; /* skip disks that didn't start mirroring */ - if (!disk->blockJobSync) + if (!diskPriv->blockJobSync) continue; if (qemuMigrationCancelOneDriveMirror(driver, vm, disk) < 0) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 56719eb..2b3d9b5 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1001,6 +1001,7 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED, virQEMUDriverPtr driver = opaque; struct qemuProcessEvent *processEvent = NULL; virDomainDiskDefPtr disk; + qemuDomainDiskPrivatePtr diskPriv; char *data = NULL; virObjectLock(vm); @@ -1010,12 +1011,13 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED, if (!(disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias))) goto error; + diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); - if (disk->blockJobSync) { - disk->blockJobType = type; - disk->blockJobStatus = status; + if (diskPriv->blockJobSync) { + diskPriv->blockJobType = type; + diskPriv->blockJobStatus = status; /* We have an SYNC API waiting for this event, dispatch it back */ - virCondSignal(&disk->blockJobSyncCond); + virCondSignal(&diskPriv->blockJobSyncCond); } else { /* there is no waiting SYNC API, dispatch the update to a thread */ if (VIR_ALLOC(processEvent) < 0) @@ -5063,9 +5065,10 @@ void qemuProcessStop(virQEMUDriverPtr driver, /* Wake up anything waiting on synchronous block jobs */ for (i = 0; i < vm->def->ndisks; i++) { - virDomainDiskDefPtr disk = vm->def->disks[i]; - if (disk->blockJobSync && disk->blockJobStatus == -1) - virCondSignal(&disk->blockJobSyncCond); + qemuDomainDiskPrivatePtr diskPriv = + QEMU_DOMAIN_DISK_PRIVATE(vm->def->disks[i]); + if (diskPriv->blockJobSync && diskPriv->blockJobStatus == -1) + virCondSignal(&diskPriv->blockJobSyncCond); } if ((logfile = qemuDomainCreateLog(driver, vm, true)) < 0) { -- 2.4.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list