There's no way to cancel the current executing dump process, lead to the
virtual machine manager daemon((e.g. libvirtd) cannot restore the dump
job after daemon restart.

When caller pass the 'job-id' argument, create a job for dump process.
And then caller can use job-cancel QMP command to cancel the detached
dump process, use job-dismiss QMP command to release job object.

Examples:
Start dump job:
{"execute": "dump-guest-memory", "arguments": { "job-id": "dump-guest-memory",
                                                "protocol": "file:/tmp/vm.dump",
                                                "paging": false,
                                                "format": "elf",
                                                "detach": true
                                              }}

Cancel dump job:
{"execute": "job-cancel", "arguments": { "id": "dump-guest-memory" }}

Dismiss dump job:
{"execute": "job-dismiss", "arguments": { "id": "dump-guest-memory" }}

Signed-off-by: Hogan Wang <[email protected]>
---
 dump/dump.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/dump/dump.c b/dump/dump.c
index cec9be30b4..f2f3b6726f 100644
--- a/dump/dump.c
+++ b/dump/dump.c
@@ -98,6 +98,7 @@ static int dump_cleanup(DumpState *s)
 {
     guest_phys_blocks_free(&s->guest_phys_blocks);
     memory_mapping_list_free(&s->list);
+    s->job = NULL;
     close(s->fd);
     g_free(s->guest_note);
     s->guest_note = NULL;
@@ -1542,6 +1543,14 @@ static void get_max_mapnr(DumpState *s)
 
 static DumpState dump_state_global = { .status = DUMP_STATUS_NONE };
 
+typedef struct DumpJob {
+    Job common;
+    DumpState *state;
+    Coroutine *co;
+    Error **errp;
+} DumpJob;
+
+
 static void dump_state_prepare(DumpState *s)
 {
     /* zero the struct, setting status to active */
@@ -1894,6 +1903,53 @@ DumpQueryResult *qmp_query_dump(Error **errp)
     return result;
 }
 
+static void *dump_job_thread(void *opaque)
+{
+    DumpJob *job = (DumpJob *)opaque;
+    job_progress_set_remaining(&job->common, 1);
+    dump_process(job->state, job->errp);
+    job_progress_update(&job->common, 1);
+    aio_co_wake(job->co);
+    return NULL;
+}
+
+static int coroutine_fn dump_guest_memory_job_run(Job *job, Error **errp)
+{
+    DumpJob *s = container_of(job, DumpJob, common);
+    DumpState *state = &dump_state_global;
+
+    s->errp = errp;
+    s->co = qemu_coroutine_self();
+
+    /* detached dump */
+    qemu_thread_create(&s->state->dump_thread, "dump_thread",
+                       dump_job_thread, job, QEMU_THREAD_DETACHED);
+    qemu_coroutine_yield();
+    return qatomic_read(&state->status) == DUMP_STATUS_COMPLETED ? 0 : -1;
+}
+
+static const JobDriver dump_guest_memory_job_driver = {
+    .instance_size = sizeof(DumpJob),
+    .job_type      = JOB_TYPE_DUMP_GUEST_MEMORY,
+    .run           = dump_guest_memory_job_run,
+};
+
+static void dump_job_start(DumpState *state, const char *job_id, Error **errp)
+{
+    DumpJob *job;
+
+    job = job_create(job_id, &dump_guest_memory_job_driver, NULL,
+                     qemu_get_aio_context(), JOB_MANUAL_DISMISS,
+                     NULL, NULL, errp);
+    if (!job) {
+        return;
+    }
+    state->detached = true;
+    state->job = &job->common;
+    job->state = state;
+    job_start(&job->common);
+}
+
 void qmp_dump_guest_memory(bool paging, const char *file,
                            bool has_job_id, const char *job_id,
                            bool has_detach, bool detach,
@@ -2010,6 +2066,15 @@ void qmp_dump_guest_memory(bool paging, const char *file,
         return;
     }
 
+    if (has_job_id) {
+        dump_job_start(s, job_id, errp);
+        if (*errp) {
+            qatomic_set(&s->status, DUMP_STATUS_FAILED);
+            dump_cleanup(s);
+        }
+        return;
+    }
+
     if (detach_p) {
         /* detached dump */
         s->detached = true;
-- 
2.33.0


Reply via email to