diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index d018ac259d..6c145c7d82 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -51,6 +51,7 @@ module Libvirtd_qemu = | bool_entry "set_process_name" | int_entry "max_processes" | str_entry "lock_manager" + | int_entry "max_queued" (* Each enty in the config is one of the following three ... *) let entry = vnc_entry diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 79c6e8510b..4da5d5a13f 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -309,3 +309,10 @@ # disk), uncomment this # # lock_manager = "sanlock" + +# Set limit of maximum APIs queued on one domain. All other APIs +# over this threshold will fail on acquiring job lock. Specially, +# setting to zero turns this feature off. +# Note, that job lock is per domain. +# +# max_queued = 0 diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 443e08d7bb..d1bf075659 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -458,6 +458,10 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, VIR_FREE(lockConf); } + p = virConfGetValue(conf, "max_queued"); + CHECK_TYPE("max_queued", VIR_CONF_LONG); + if (p) driver->max_queued = p->l; + virConfFree (conf); return 0; } diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 5469a63abe..e8b92a4982 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -109,6 +109,8 @@ struct qemud_driver { int maxProcesses; + int max_queued; + virCapsPtr caps; virDomainEventStatePtr domainEventState; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 675c6dff9b..982bad6c7e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -713,6 +713,8 @@ qemuDomainObjBeginJobInternal(struct qemud_driver *driver, unsigned long long then; bool nested = job == QEMU_JOB_ASYNC_NESTED; + priv->jobs_queued++; + if (virTimeMs(&now) < 0) return -1; then = now + QEMU_JOB_WAIT_TIME; @@ -722,6 +724,11 @@ qemuDomainObjBeginJobInternal(struct qemud_driver *driver, qemuDriverUnlock(driver); retry: + if (driver->max_queued && + priv->jobs_queued > driver->max_queued) { + goto error; + } + while (!nested && !qemuDomainJobAllowed(priv, job)) { if (virCondWaitUntil(&priv->job.asyncCond, &obj->lock, then) < 0) goto error; @@ -761,9 +768,15 @@ error: if (errno == ETIMEDOUT) qemuReportError(VIR_ERR_OPERATION_TIMEOUT, "%s", _("cannot acquire state change lock")); + else if (driver->max_queued && + priv->jobs_queued > driver->max_queued) + qemuReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("cannot acquire state change lock " + "due to max_queued limit")); else virReportSystemError(errno, "%s", _("cannot acquire job mutex")); + priv->jobs_queued--; if (driver_locked) { virDomainObjUnlock(obj); qemuDriverLock(driver); @@ -844,6 +857,8 @@ int qemuDomainObjEndJob(struct qemud_driver *driver, virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; + priv->jobs_queued--; + qemuDomainObjResetJob(priv); qemuDomainObjSaveJob(driver, obj); virCondSignal(&priv->job.cond); @@ -856,6 +871,8 @@ qemuDomainObjEndAsyncJob(struct qemud_driver *driver, virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; + priv->jobs_queued--; + qemuDomainObjResetAsyncJob(priv); qemuDomainObjSaveJob(driver, obj); virCondBroadcast(&priv->job.asyncCond); diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index e12ca8e8f6..55875fe4de 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -113,6 +113,8 @@ struct _qemuDomainObjPrivate { char *lockState; bool fakeReboot; + + int jobs_queued; }; struct qemuDomainWatchdogEvent