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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
---
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@xxxxxxxxxx>

Jano

Attachment: signature.asc
Description: PGP signature

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux