diff --git a/po/POTFILES.in b/po/POTFILES.in index dd06ab3c524b520c1a490c0a25e85e9ca4d55d98..bb0f6e1543491ece6065553fb36e6c9f8b5bb0ff 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -112,6 +112,7 @@ src/parallels/parallels_utils.h src/parallels/parallels_storage.c src/phyp/phyp_driver.c src/qemu/qemu_agent.c +src/qemu/qemu_blockjob.c src/qemu/qemu_capabilities.c src/qemu/qemu_cgroup.c src/qemu/qemu_command.c diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index e61ad8cce62ed8b8221dc7106c29f1b966f8ec4f..729928a7514c0296bb3287cc9e2712d294f19198 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -31,6 +31,8 @@ #include "virlog.h" #include "virstoragefile.h" +#include "virthread.h" +#include "virtime.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -165,3 +167,165 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, virObjectUnref(cfg); } + + +/** + * qemuBlockJobSyncBegin: + * @disk: domain disk + * + * Begin a new synchronous block job for @disk. The synchronous + * block job is ended by a call to qemuBlockJobSyncEnd, or by + * the guest quitting. + * + * During a synchronous block job, a block job event for @disk + * will not be processed asynchronously. Instead, it will be + * processed only when qemuBlockJobSyncWait* or + * qemuBlockJobSyncEnd is called. + */ +void +qemuBlockJobSyncBegin(virDomainDiskDefPtr disk) +{ + if (disk->blockJobSync) + VIR_WARN("Disk %s already has synchronous block job", + disk->dst); + + disk->blockJobSync = true; +} + + +/** + * qemuBlockJobSyncEnd: + * @driver: qemu driver + * @vm: domain + * @disk: domain disk + * @ret_status: pointer to virConnectDomainEventBlockJobStatus + * + * End a synchronous block job for @disk. Any pending block job event + * for the disk is processed, and its status is recorded in the + * virConnectDomainEventBlockJobStatus field pointed to by + * @ret_status. + */ +void +qemuBlockJobSyncEnd(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk, + virConnectDomainEventBlockJobStatus *ret_status) +{ + if (disk->blockJobSync && disk->blockJobStatus != -1) { + if (ret_status) + *ret_status = disk->blockJobStatus; + qemuBlockJobEventProcess(driver, vm, disk, + disk->blockJobType, + disk->blockJobStatus); + disk->blockJobStatus = -1; + } + disk->blockJobSync = false; +} + + +/** + * qemuBlockJobSyncWaitWithTimeout: + * @driver: qemu driver + * @vm: domain + * @disk: domain disk + * @timeout: timeout in milliseconds + * @ret_status: pointer to virConnectDomainEventBlockJobStatus + * + * Wait up to @timeout milliseconds for a block job event for @disk. + * If an event is received it is processed, and its status is recorded + * in the virConnectDomainEventBlockJobStatus field pointed to by + * @ret_status. + * + * If @timeout is not 0, @vm will be unlocked while waiting for the event. + * + * Returns 0 if an event was received or the timeout expired, + * -1 otherwise. + */ +int +qemuBlockJobSyncWaitWithTimeout(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk, + unsigned long long timeout, + virConnectDomainEventBlockJobStatus *ret_status) +{ + if (!disk->blockJobSync) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No current synchronous block job")); + return -1; + } + + while (disk->blockJobSync && disk->blockJobStatus == -1) { + int r; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("guest unexpectedly quit")); + disk->blockJobSync = false; + return -1; + } + + if (timeout == (unsigned long long)-1) { + r = virCondWait(&disk->blockJobSyncCond, &vm->parent.lock); + } else if (timeout) { + unsigned long long now; + if (virTimeMillisNow(&now) < 0) { + virReportSystemError(errno, "%s", + _("Unable to get current time")); + return -1; + } + r = virCondWaitUntil(&disk->blockJobSyncCond, &vm->parent.lock, + now + timeout); + if (r < 0 && errno == ETIMEDOUT) + return 0; + } else { + errno = ETIMEDOUT; + return 0; + } + + if (r < 0) { + disk->blockJobSync = false; + virReportSystemError(errno, "%s", + _("Unable to wait on block job sync " + "condition")); + return -1; + } + } + + if (ret_status) + *ret_status = disk->blockJobStatus; + qemuBlockJobEventProcess(driver, vm, disk, + disk->blockJobType, + disk->blockJobStatus); + disk->blockJobStatus = -1; + + return 0; +} + + +/** + * qemuBlockJobSyncWait: + * @driver: qemu driver + * @vm: domain + * @disk: domain disk + * @ret_status: pointer to virConnectDomainEventBlockJobStatus + * + * Wait for a block job event for @disk. If an event is received it + * is processed, and its status is recorded in the + * virConnectDomainEventBlockJobStatus field pointed to by + * @ret_status. + * + * @vm will be unlocked while waiting for the event. + * + * Returns 0 if an event was received, + * -1 otherwise. + */ +int +qemuBlockJobSyncWait(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk, + virConnectDomainEventBlockJobStatus *ret_status) +{ + return qemuBlockJobSyncWaitWithTimeout(driver, vm, disk, + (unsigned long long)-1, + ret_status); +} diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h index abe1aa5e49d481e4fabb2ef5d19e61039d5a7b96..ba372a20bf0d30f2e721b00c33f49f1696ab834f 100644 --- a/src/qemu/qemu_blockjob.h +++ b/src/qemu/qemu_blockjob.h @@ -22,6 +22,7 @@ #ifndef __QEMU_BLOCKJOB_H__ # define __QEMU_BLOCKJOB_H__ +# include "internal.h" # include "qemu_conf.h" void qemuBlockJobEventProcess(virQEMUDriverPtr driver, @@ -30,4 +31,19 @@ void qemuBlockJobEventProcess(virQEMUDriverPtr driver, int type, int status); +void qemuBlockJobSyncBegin(virDomainDiskDefPtr disk); +void qemuBlockJobSyncEnd(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk, + virConnectDomainEventBlockJobStatus *ret_status); +int qemuBlockJobSyncWaitWithTimeout(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk, + unsigned long long timeout, + virConnectDomainEventBlockJobStatus *ret_status); +int qemuBlockJobSyncWait(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk, + virConnectDomainEventBlockJobStatus *ret_status); + #endif /* __QEMU_BLOCKJOB_H__ */