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 7641fd7..5e787ce 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,
@@ -8811,6 +8826,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",
@@ -8891,7 +8949,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 0bf03df..cea92fd 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -1899,6 +1899,42 @@ cleanup:
}
/*
+ * "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
*/
static const vshCmdInfo info_freecell[] = {
@@ -7613,6 +7649,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},
--
1.6.6