[libvirt] [PATCH 19/25] qemu: process: Refresh -blockdev based blockjobs on reconnect to qemu

Ján Tomko jtomko at redhat.com
Mon Jul 15 15:42:51 UTC 2019


On Fri, Jul 12, 2019 at 06:06:00PM +0200, Peter Krempa wrote:
>Refresh the state of the jobs and process any events that might have
>happened while libvirt was not running.
>
>The job state processing requires some care to figure out if a job
>needs to be bumped.
>
>For any invalid job try doing our best to cancel it.
>
>Signed-off-by: Peter Krempa <pkrempa at redhat.com>
>---
> src/qemu/qemu_blockjob.c | 109 +++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_blockjob.h |   5 ++
> src/qemu/qemu_process.c  |   7 ++-
> 3 files changed, 120 insertions(+), 1 deletion(-)
>
>diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
>index 8b142f1aba..360fc40e61 100644
>--- a/src/qemu/qemu_blockjob.c
>+++ b/src/qemu/qemu_blockjob.c
>@@ -242,6 +242,115 @@ qemuBlockJobIsRunning(qemuBlockJobDataPtr job)
> }
>
>
>+/* returns 1 for a job we didn't reconnect to */
>+static int
>+qemuBlockJobRefreshJobsFindInactive(const void *payload,
>+                                    const void *name ATTRIBUTE_UNUSED,
>+                                    const void *data ATTRIBUTE_UNUSED)
>+{
>+    const qemuBlockJobData *job = payload;
>+
>+    return !job->reconnected;
>+}
>+
>+
>+int
>+qemuBlockJobRefreshJobs(virQEMUDriverPtr driver,
>+                        virDomainObjPtr vm)
>+{
>+    qemuDomainObjPrivatePtr priv = vm->privateData;
>+    qemuMonitorJobInfoPtr *jobinfo = NULL;
>+    size_t njobinfo = 0;
>+    qemuBlockJobDataPtr job = NULL;
>+    int newstate;
>+    size_t i;
>+    int ret = -1;
>+    int rc;
>+
>+    qemuDomainObjEnterMonitor(driver, vm);
>+
>+    rc = qemuMonitorGetJobInfo(priv->mon, &jobinfo, &njobinfo);
>+
>+    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
>+        goto cleanup;
>+
>+    for (i = 0; i < njobinfo; i++) {
>+        if (!(job = virHashLookup(priv->blockjobs, jobinfo[i]->id))) {
>+            VIR_DEBUG("ignoring untracked job '%s'", jobinfo[i]->id);
>+            continue;
>+        }
>+
>+        /* try cancelling invalid jobs - this works only if the job is not
>+         * concluded. In such case it will fail. We'll leave such job linger
>+         * in qemu and just forget about it in libvirt because there's not much
>+         * we coud do besides killing the VM */
>+        if (job->invalidData) {
>+            qemuDomainObjEnterMonitor(driver, vm);
>+
>+            rc = qemuMonitorJobCancel(priv->mon, job->name, true);
>+            if (rc == -1 && jobinfo[i]->status == QEMU_MONITOR_JOB_STATUS_CONCLUDED)
>+                VIR_WARN("can't cancel job '%s' with invalid data", job->name);
>+
>+            if (qemuDomainObjExitMonitor(driver, vm) < 0)
>+                goto cleanup;
>+
>+            if (rc < 0)
>+                qemuBlockJobUnregister(job, vm);
>+            job = NULL;

The value is unused after this.

>+            continue;
>+        }
>+
>+        if ((newstate = qemuBlockjobConvertMonitorStatus(jobinfo[i]->status)) < 0)
>+            continue;
>+
>+        if (newstate != job->state) {
>+            if ((job->state == QEMU_BLOCKJOB_STATE_FAILED ||
>+                 job->state == QEMU_BLOCKJOB_STATE_COMPLETED)) {
>+                /* preserve the old state but allow the job to be bumped to
>+                 * execute the finishing steps */
>+                job->newstate = job->state;
>+            } else if (newstate == QEMU_BLOCKJOB_STATE_CONCLUDED) {
>+                if (VIR_STRDUP(job->errmsg, jobinfo[i]->error) < 0)
>+                    goto cleanup;
>+
>+                if (job->errmsg)
>+                    job->newstate = QEMU_BLOCKJOB_STATE_FAILED;
>+                else
>+                    job->newstate = QEMU_BLOCKJOB_STATE_COMPLETED;
>+            } else if (newstate == QEMU_BLOCKJOB_STATE_READY) {
>+                /* Apply _READY state only if it was not applied before */
>+                if (job->state == QEMU_BLOCKJOB_STATE_NEW ||
>+                    job->state == QEMU_BLOCKJOB_STATE_RUNNING)
>+                    job->newstate = newstate;
>+            }
>+            /* don't update the job otherwise */
>+        }
>+
>+        job->reconnected = true;
>+
>+        if (job->newstate != -1)
>+            qemuBlockJobUpdate(vm, job, QEMU_ASYNC_JOB_NONE);
>+        job = NULL; /* job may have become invalid here */
>+    }
>+
>+    /* remove data for job which qemu didn't report (the algorithm is
>+     * inefficient, but the possibility of such jobs is very low */
>+    while ((job = virHashSearch(priv->blockjobs, qemuBlockJobRefreshJobsFindInactive, NULL, NULL))) {
>+        qemuBlockJobUnregister(job, vm);
>+        job = NULL;
>+    }
>+
>+    ret = 0;
>+
>+ cleanup:
>+    for (i = 0; i < njobinfo; i++)
>+        qemuMonitorJobInfoFree(jobinfo[i]);
>+    VIR_FREE(jobinfo);
>+
>+    return ret;
>+}
>+
>+
> /**
>  * qemuBlockJobEmitEvents:
>  *

Reviewed-by: Ján Tomko <jtomko at redhat.com>

Jano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20190715/6b20f713/attachment-0001.sig>


More information about the libvir-list mailing list