From 04c7abd9c349ef2157e92785bff45b6325895f3e Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 3 Feb 2010 19:11:27 +0000 Subject: [PATCH] Support job cancellation in QEMU driver This supports cancellation of jobs for the QEMU driver against the virDomainMigrate, virDomainSave and virDomainCoreDump APIs. It is not yet supported for the virDomainRestore API, although it is desirable. * src/qemu/qemu_driver.c: Issue 'migrate_cancel' command if virDomainAbortJob is issued during a migration operation * tools/virsh.c: Add a domjobabort command --- src/qemu/qemu_driver.c | 66 +++++++++++++++++++++++++++++++++++++++--- tools/virsh.c | 37 +++++++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 081b698f7f..d03c235905 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -84,9 +84,10 @@ typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate; typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr; struct _qemuDomainObjPrivate { virCond jobCond; /* Use in conjunction with main virDomainObjPtr lock */ - int jobActive; /* Non-zero if a job is active. Only 1 job is allowed at any time - * A job includes *all* monitor commands, even those just querying - * information, not merely actions */ + unsigned int jobActive : 1; /* Non-zero if a job is active. Only 1 job is allowed at any time + * A job includes *all* monitor commands, even those just querying + * information, not merely actions */ + unsigned int jobCancel : 1; /* Non-zero if a cancel request from client has arrived */ virDomainJobInfo jobInfo; unsigned long long jobStart; @@ -331,6 +332,7 @@ static int qemuDomainObjBeginJob(virDomainObjPtr obj) } } priv->jobActive = 1; + priv->jobCancel = 0; priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); @@ -377,6 +379,7 @@ static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, } } priv->jobActive = 1; + priv->jobCancel = 0; priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); @@ -401,6 +404,7 @@ static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj) qemuDomainObjPrivatePtr priv = obj->privateData; priv->jobActive = 0; + priv->jobCancel = 0; priv->jobStart = 0; memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virCondSignal(&priv->jobCond); @@ -3945,6 +3949,17 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr struct timeval now; int rc; + if (priv->jobCancel) { + priv->jobCancel = 0; + VIR_DEBUG0("Cancelling migration at client request"); + qemuDomainObjEnterMonitorWithDriver(driver, vm); + rc = qemuMonitorMigrateCancel(priv->mon); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (rc < 0) { + VIR_WARN0("Unable to cancel migration"); + } + } + qemuDomainObjEnterMonitorWithDriver(driver, vm); rc = qemuMonitorGetMigrationStatus(priv->mon, &status, @@ -8838,6 +8853,49 @@ cleanup: } +static int qemuDomainAbortJob(virDomainPtr dom) { + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + priv = vm->privateData; + + if (virDomainObjIsActive(vm)) { + if (priv->jobActive) { + VIR_DEBUG("Requesting cancellation of job on vm %s", vm->def->name); + priv->jobCancel = 1; + } else { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("no job is active on the domain")); + goto cleanup; + } + } else { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -8918,7 +8976,7 @@ static virDriver qemuDriver = { qemuCPUCompare, /* cpuCompare */ qemuCPUBaseline, /* cpuBaseline */ qemuDomainGetJobInfo, /* domainGetJobInfo */ - NULL, /* domainFinishJob */ + qemuDomainAbortJob, /* domainAbortJob */ }; diff --git a/tools/virsh.c b/tools/virsh.c index b36fcefaf8..a6a637d1ba 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -1906,6 +1906,42 @@ cleanup: return ret; } +/* + * "domjobabort" command + */ +static const vshCmdInfo info_domjobabort[] = { + {"help", gettext_noop("abort active domain job")}, + {"desc", gettext_noop("Aborts the currently running domain job")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domjobabort[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdDomjobabort(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret = TRUE; + unsigned int id; + char *str, uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + if (virDomainAbortJob(dom) < 0) + ret = FALSE; + +cleanup: + virDomainFree(dom); + return ret; +} + /* * "freecell" command */ @@ -7621,6 +7657,7 @@ static const vshCmdDef commands[] = { {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid}, {"dominfo", cmdDominfo, opts_dominfo, info_dominfo}, {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo}, + {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort}, {"domname", cmdDomname, opts_domname, info_domname}, {"domstate", cmdDomstate, opts_domstate, info_domstate}, {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat}, -- GitLab