Current, we support run sync job and async job at the same time. It means that the
monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, priv->job.active
is QEMU_JOB_NONE if no sync job is running, or priv->job.active is not
QEMU_JOB_NONE if a sync job is running. So we cannot check whether the
caller is an async job in the function qemuDomainObjEnterMonitorInternal().
Unfortunately, if sync job and async job are running at the same time, we may
try to send monitor command at the same time in two threads. It's very
dangerous, and it will cause libvirtd crashed.
We should enhance the function qemuMonitorSend() to support it to be called
at the same time.
If the last monitor command does not finish, the other monitor commands should
wait it to finish.
---
src/qemu/qemu_monitor.c | 22 +++++++++++++++++++++-
1 files changed, 21 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index db6107c..a10f53f 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -46,6 +46,8 @@ struct _qemuMonitor {
virMutex lock; /* also used to protect fd */
virCond notify;
+ virCond send_notify;
+
int refs;
int fd;
@@ -675,7 +677,8 @@ qemuMonitorOpen(virDomainObjPtr vm,
VIR_FREE(mon);
return NULL;
}
- if (virCondInit(&mon->notify) < 0) {
+ if ((virCondInit(&mon->notify) < 0) ||
+ (virCondInit(&mon->send_notify) < 0)) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot initialize monitor condition"));
virMutexDestroy(&mon->lock);
@@ -795,6 +798,22 @@ int qemuMonitorSend(qemuMonitorPtr mon,
return -1;
}
+ while (mon->msg) {
+ if (virCondWait(&mon->send_notify, &mon->lock) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to wait on monitor condition"));
+ goto cleanup;
+ }
+ }
+
+ /* Check whether qemu quited unexpectedly again */
+ if (mon->lastError.code != VIR_ERR_OK) {
+ VIR_DEBUG("Attempt to send command while error is set %s",
+ NULLSTR(mon->lastError.message));
+ virSetError(&mon->lastError);
+ return -1;
+ }
+
mon->msg = msg;
qemuMonitorUpdateWatch(mon);
@@ -818,6 +837,7 @@ int qemuMonitorSend(qemuMonitorPtr mon,
cleanup:
mon->msg = NULL;
qemuMonitorUpdateWatch(mon);
+ virCondBroadcast(&mon->send_notify);
return ret;
}
--
1.7.1