26ba25
From c0a6a1f61a194ab1a96b0f722b9ddca7398f7dde Mon Sep 17 00:00:00 2001
26ba25
From: Kevin Wolf <kwolf@redhat.com>
26ba25
Date: Tue, 26 Jun 2018 09:47:59 +0200
26ba25
Subject: [PATCH 091/268] job: Create Job, JobDriver and job_create()
26ba25
26ba25
RH-Author: Kevin Wolf <kwolf@redhat.com>
26ba25
Message-id: <20180626094856.6924-17-kwolf@redhat.com>
26ba25
Patchwork-id: 81124
26ba25
O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 16/73] job: Create Job, JobDriver and job_create()
26ba25
Bugzilla: 1513543
26ba25
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
26ba25
RH-Acked-by: Max Reitz <mreitz@redhat.com>
26ba25
RH-Acked-by: Fam Zheng <famz@redhat.com>
26ba25
26ba25
This is the first step towards creating an infrastructure for generic
26ba25
background jobs that aren't tied to a block device. For now, Job only
26ba25
stores its ID and JobDriver, the rest stays in BlockJob.
26ba25
26ba25
The following patches will move over more parts of BlockJob to Job if
26ba25
they are meaningful outside the context of a block job.
26ba25
26ba25
BlockJob.driver is now redundant, but this patch leaves it around to
26ba25
avoid unnecessary churn. The next patches will get rid of almost all of
26ba25
its uses anyway so that it can be removed later with much less churn.
26ba25
26ba25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26ba25
Reviewed-by: Max Reitz <mreitz@redhat.com>
26ba25
Reviewed-by: John Snow <jsnow@redhat.com>
26ba25
(cherry picked from commit 33e9e9bd62d9ae00880d9e12ad8a5b7d2c00e8a5)
26ba25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26ba25
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
26ba25
---
26ba25
 MAINTAINERS                  |  2 ++
26ba25
 Makefile.objs                |  2 +-
26ba25
 block/backup.c               |  4 ++-
26ba25
 block/commit.c               |  4 ++-
26ba25
 block/mirror.c               | 10 +++++---
26ba25
 block/stream.c               |  4 ++-
26ba25
 blockjob.c                   | 46 ++++++++++++++++-----------------
26ba25
 include/block/blockjob.h     |  9 +++----
26ba25
 include/block/blockjob_int.h |  4 +--
26ba25
 include/qemu/job.h           | 60 ++++++++++++++++++++++++++++++++++++++++++++
26ba25
 job.c                        | 48 +++++++++++++++++++++++++++++++++++
26ba25
 tests/test-bdrv-drain.c      |  4 ++-
26ba25
 tests/test-blockjob-txn.c    |  4 ++-
26ba25
 tests/test-blockjob.c        | 12 ++++++---
26ba25
 14 files changed, 169 insertions(+), 44 deletions(-)
26ba25
 create mode 100644 include/qemu/job.h
26ba25
 create mode 100644 job.c
26ba25
26ba25
diff --git a/MAINTAINERS b/MAINTAINERS
26ba25
index ad5edc8..c5e3dfb 100644
26ba25
--- a/MAINTAINERS
26ba25
+++ b/MAINTAINERS
26ba25
@@ -1371,6 +1371,8 @@ L: qemu-block@nongnu.org
26ba25
 S: Supported
26ba25
 F: blockjob.c
26ba25
 F: include/block/blockjob.h
26ba25
+F: job.c
26ba25
+F: include/block/job.h
26ba25
 F: block/backup.c
26ba25
 F: block/commit.c
26ba25
 F: block/stream.c
26ba25
diff --git a/Makefile.objs b/Makefile.objs
26ba25
index c6c9b8f..92b73fc 100644
26ba25
--- a/Makefile.objs
26ba25
+++ b/Makefile.objs
26ba25
@@ -63,7 +63,7 @@ chardev-obj-y = chardev/
26ba25
 # block-obj-y is code used by both qemu system emulation and qemu-img
26ba25
 
26ba25
 block-obj-y += nbd/
26ba25
-block-obj-y += block.o blockjob.o
26ba25
+block-obj-y += block.o blockjob.o job.o
26ba25
 block-obj-y += block/ scsi/
26ba25
 block-obj-y += qemu-io-cmds.o
26ba25
 block-obj-$(CONFIG_REPLICATION) += replication.o
26ba25
diff --git a/block/backup.c b/block/backup.c
26ba25
index e14d995..9e672bb 100644
26ba25
--- a/block/backup.c
26ba25
+++ b/block/backup.c
26ba25
@@ -523,7 +523,9 @@ static void coroutine_fn backup_run(void *opaque)
26ba25
 }
26ba25
 
26ba25
 static const BlockJobDriver backup_job_driver = {
26ba25
-    .instance_size          = sizeof(BackupBlockJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size          = sizeof(BackupBlockJob),
26ba25
+    },
26ba25
     .job_type               = BLOCK_JOB_TYPE_BACKUP,
26ba25
     .start                  = backup_run,
26ba25
     .commit                 = backup_commit,
26ba25
diff --git a/block/commit.c b/block/commit.c
26ba25
index ba5df6a..18cbb2f 100644
26ba25
--- a/block/commit.c
26ba25
+++ b/block/commit.c
26ba25
@@ -215,7 +215,9 @@ out:
26ba25
 }
26ba25
 
26ba25
 static const BlockJobDriver commit_job_driver = {
26ba25
-    .instance_size = sizeof(CommitBlockJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size = sizeof(CommitBlockJob),
26ba25
+    },
26ba25
     .job_type      = BLOCK_JOB_TYPE_COMMIT,
26ba25
     .start         = commit_run,
26ba25
 };
26ba25
diff --git a/block/mirror.c b/block/mirror.c
26ba25
index a4197bb..aa1d6b7 100644
26ba25
--- a/block/mirror.c
26ba25
+++ b/block/mirror.c
26ba25
@@ -913,7 +913,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
26ba25
 
26ba25
     if (!s->synced) {
26ba25
         error_setg(errp, "The active block job '%s' cannot be completed",
26ba25
-                   job->id);
26ba25
+                   job->job.id);
26ba25
         return;
26ba25
     }
26ba25
 
26ba25
@@ -986,7 +986,9 @@ static void mirror_drain(BlockJob *job)
26ba25
 }
26ba25
 
26ba25
 static const BlockJobDriver mirror_job_driver = {
26ba25
-    .instance_size          = sizeof(MirrorBlockJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size          = sizeof(MirrorBlockJob),
26ba25
+    },
26ba25
     .job_type               = BLOCK_JOB_TYPE_MIRROR,
26ba25
     .start                  = mirror_run,
26ba25
     .complete               = mirror_complete,
26ba25
@@ -996,7 +998,9 @@ static const BlockJobDriver mirror_job_driver = {
26ba25
 };
26ba25
 
26ba25
 static const BlockJobDriver commit_active_job_driver = {
26ba25
-    .instance_size          = sizeof(MirrorBlockJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size          = sizeof(MirrorBlockJob),
26ba25
+    },
26ba25
     .job_type               = BLOCK_JOB_TYPE_COMMIT,
26ba25
     .start                  = mirror_run,
26ba25
     .complete               = mirror_complete,
26ba25
diff --git a/block/stream.c b/block/stream.c
26ba25
index df9660d..f88fc75 100644
26ba25
--- a/block/stream.c
26ba25
+++ b/block/stream.c
26ba25
@@ -209,7 +209,9 @@ out:
26ba25
 }
26ba25
 
26ba25
 static const BlockJobDriver stream_job_driver = {
26ba25
-    .instance_size = sizeof(StreamBlockJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size = sizeof(StreamBlockJob),
26ba25
+    },
26ba25
     .job_type      = BLOCK_JOB_TYPE_STREAM,
26ba25
     .start         = stream_run,
26ba25
 };
26ba25
diff --git a/blockjob.c b/blockjob.c
26ba25
index 112672a..1464856 100644
26ba25
--- a/blockjob.c
26ba25
+++ b/blockjob.c
26ba25
@@ -34,7 +34,6 @@
26ba25
 #include "qapi/qapi-events-block-core.h"
26ba25
 #include "qapi/qmp/qerror.h"
26ba25
 #include "qemu/coroutine.h"
26ba25
-#include "qemu/id.h"
26ba25
 #include "qemu/timer.h"
26ba25
 
26ba25
 /* Right now, this mutex is only needed to synchronize accesses to job->busy
26ba25
@@ -92,7 +91,8 @@ static int block_job_apply_verb(BlockJob *job, BlockJobVerb bv, Error **errp)
26ba25
         return 0;
26ba25
     }
26ba25
     error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'",
26ba25
-               job->id, BlockJobStatus_str(job->status), BlockJobVerb_str(bv));
26ba25
+               job->job.id, BlockJobStatus_str(job->status),
26ba25
+               BlockJobVerb_str(bv));
26ba25
     return -EPERM;
26ba25
 }
26ba25
 
26ba25
@@ -159,7 +159,7 @@ BlockJob *block_job_get(const char *id)
26ba25
     BlockJob *job;
26ba25
 
26ba25
     QLIST_FOREACH(job, &block_jobs, job_list) {
26ba25
-        if (job->id && !strcmp(id, job->id)) {
26ba25
+        if (job->job.id && !strcmp(id, job->job.id)) {
26ba25
             return job;
26ba25
         }
26ba25
     }
26ba25
@@ -261,7 +261,7 @@ void block_job_unref(BlockJob *job)
26ba25
                                         block_job_detach_aio_context, job);
26ba25
         blk_unref(job->blk);
26ba25
         error_free(job->blocker);
26ba25
-        g_free(job->id);
26ba25
+        g_free(job->job.id);
26ba25
         assert(!timer_pending(&job->sleep_timer));
26ba25
         g_free(job);
26ba25
     }
26ba25
@@ -311,7 +311,7 @@ static char *child_job_get_parent_desc(BdrvChild *c)
26ba25
     BlockJob *job = c->opaque;
26ba25
     return g_strdup_printf("%s job '%s'",
26ba25
                            BlockJobType_str(job->driver->job_type),
26ba25
-                           job->id);
26ba25
+                           job->job.id);
26ba25
 }
26ba25
 
26ba25
 static void child_job_drained_begin(BdrvChild *c)
26ba25
@@ -365,7 +365,7 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
26ba25
 
26ba25
 bool block_job_is_internal(BlockJob *job)
26ba25
 {
26ba25
-    return (job->id == NULL);
26ba25
+    return (job->job.id == NULL);
26ba25
 }
26ba25
 
26ba25
 static bool block_job_started(BlockJob *job)
26ba25
@@ -705,13 +705,13 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n)
26ba25
 void block_job_complete(BlockJob *job, Error **errp)
26ba25
 {
26ba25
     /* Should not be reachable via external interface for internal jobs */
26ba25
-    assert(job->id);
26ba25
+    assert(job->job.id);
26ba25
     if (block_job_apply_verb(job, BLOCK_JOB_VERB_COMPLETE, errp)) {
26ba25
         return;
26ba25
     }
26ba25
     if (job->pause_count || job->cancelled || !job->driver->complete) {
26ba25
         error_setg(errp, "The active block job '%s' cannot be completed",
26ba25
-                   job->id);
26ba25
+                   job->job.id);
26ba25
         return;
26ba25
     }
26ba25
 
26ba25
@@ -720,7 +720,7 @@ void block_job_complete(BlockJob *job, Error **errp)
26ba25
 
26ba25
 void block_job_finalize(BlockJob *job, Error **errp)
26ba25
 {
26ba25
-    assert(job && job->id);
26ba25
+    assert(job && job->job.id);
26ba25
     if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) {
26ba25
         return;
26ba25
     }
26ba25
@@ -731,7 +731,7 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp)
26ba25
 {
26ba25
     BlockJob *job = *jobptr;
26ba25
     /* similarly to _complete, this is QMP-interface only. */
26ba25
-    assert(job->id);
26ba25
+    assert(job->job.id);
26ba25
     if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) {
26ba25
         return;
26ba25
     }
26ba25
@@ -848,7 +848,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
26ba25
     }
26ba25
     info = g_new0(BlockJobInfo, 1);
26ba25
     info->type      = g_strdup(BlockJobType_str(job->driver->job_type));
26ba25
-    info->device    = g_strdup(job->id);
26ba25
+    info->device    = g_strdup(job->job.id);
26ba25
     info->len       = job->len;
26ba25
     info->busy      = atomic_read(&job->busy);
26ba25
     info->paused    = job->pause_count > 0;
26ba25
@@ -879,7 +879,7 @@ static void block_job_event_cancelled(BlockJob *job)
26ba25
     }
26ba25
 
26ba25
     qapi_event_send_block_job_cancelled(job->driver->job_type,
26ba25
-                                        job->id,
26ba25
+                                        job->job.id,
26ba25
                                         job->len,
26ba25
                                         job->offset,
26ba25
                                         job->speed,
26ba25
@@ -893,7 +893,7 @@ static void block_job_event_completed(BlockJob *job, const char *msg)
26ba25
     }
26ba25
 
26ba25
     qapi_event_send_block_job_completed(job->driver->job_type,
26ba25
-                                        job->id,
26ba25
+                                        job->job.id,
26ba25
                                         job->len,
26ba25
                                         job->offset,
26ba25
                                         job->speed,
26ba25
@@ -907,7 +907,7 @@ static int block_job_event_pending(BlockJob *job)
26ba25
     block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING);
26ba25
     if (!job->auto_finalize && !block_job_is_internal(job)) {
26ba25
         qapi_event_send_block_job_pending(job->driver->job_type,
26ba25
-                                          job->id,
26ba25
+                                          job->job.id,
26ba25
                                           &error_abort);
26ba25
     }
26ba25
     return 0;
26ba25
@@ -945,12 +945,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
26ba25
             error_setg(errp, "Cannot specify job ID for internal block job");
26ba25
             return NULL;
26ba25
         }
26ba25
-
26ba25
-        if (!id_wellformed(job_id)) {
26ba25
-            error_setg(errp, "Invalid job ID '%s'", job_id);
26ba25
-            return NULL;
26ba25
-        }
26ba25
-
26ba25
         if (block_job_get(job_id)) {
26ba25
             error_setg(errp, "Job ID '%s' already in use", job_id);
26ba25
             return NULL;
26ba25
@@ -964,9 +958,13 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
26ba25
         return NULL;
26ba25
     }
26ba25
 
26ba25
-    job = g_malloc0(driver->instance_size);
26ba25
+    job = job_create(job_id, &driver->job_driver, errp);
26ba25
+    if (job == NULL) {
26ba25
+        blk_unref(blk);
26ba25
+        return NULL;
26ba25
+    }
26ba25
+
26ba25
     job->driver        = driver;
26ba25
-    job->id            = g_strdup(job_id);
26ba25
     job->blk           = blk;
26ba25
     job->cb            = cb;
26ba25
     job->opaque        = opaque;
26ba25
@@ -1187,7 +1185,7 @@ void block_job_event_ready(BlockJob *job)
26ba25
     }
26ba25
 
26ba25
     qapi_event_send_block_job_ready(job->driver->job_type,
26ba25
-                                    job->id,
26ba25
+                                    job->job.id,
26ba25
                                     job->len,
26ba25
                                     job->offset,
26ba25
                                     job->speed, &error_abort);
26ba25
@@ -1217,7 +1215,7 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
26ba25
         abort();
26ba25
     }
26ba25
     if (!block_job_is_internal(job)) {
26ba25
-        qapi_event_send_block_job_error(job->id,
26ba25
+        qapi_event_send_block_job_error(job->job.id,
26ba25
                                         is_read ? IO_OPERATION_TYPE_READ :
26ba25
                                         IO_OPERATION_TYPE_WRITE,
26ba25
                                         action, &error_abort);
26ba25
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
26ba25
index 0f56f72..640e649 100644
26ba25
--- a/include/block/blockjob.h
26ba25
+++ b/include/block/blockjob.h
26ba25
@@ -26,6 +26,7 @@
26ba25
 #ifndef BLOCKJOB_H
26ba25
 #define BLOCKJOB_H
26ba25
 
26ba25
+#include "qemu/job.h"
26ba25
 #include "block/block.h"
26ba25
 #include "qemu/ratelimit.h"
26ba25
 
26ba25
@@ -40,6 +41,9 @@ typedef struct BlockJobTxn BlockJobTxn;
26ba25
  * Long-running operation on a BlockDriverState.
26ba25
  */
26ba25
 typedef struct BlockJob {
26ba25
+    /** Data belonging to the generic Job infrastructure */
26ba25
+    Job job;
26ba25
+
26ba25
     /** The job type, including the job vtable.  */
26ba25
     const BlockJobDriver *driver;
26ba25
 
26ba25
@@ -47,11 +51,6 @@ typedef struct BlockJob {
26ba25
     BlockBackend *blk;
26ba25
 
26ba25
     /**
26ba25
-     * The ID of the block job. May be NULL for internal jobs.
26ba25
-     */
26ba25
-    char *id;
26ba25
-
26ba25
-    /**
26ba25
      * The coroutine that executes the job.  If not NULL, it is
26ba25
      * reentered when busy is false and the job is cancelled.
26ba25
      */
26ba25
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
26ba25
index 62ec964..e8eca44 100644
26ba25
--- a/include/block/blockjob_int.h
26ba25
+++ b/include/block/blockjob_int.h
26ba25
@@ -35,8 +35,8 @@
26ba25
  * A class type for block job driver.
26ba25
  */
26ba25
 struct BlockJobDriver {
26ba25
-    /** Derived BlockJob struct size */
26ba25
-    size_t instance_size;
26ba25
+    /** Generic JobDriver callbacks and settings */
26ba25
+    JobDriver job_driver;
26ba25
 
26ba25
     /** String describing the operation, part of query-block-jobs QMP API */
26ba25
     BlockJobType job_type;
26ba25
diff --git a/include/qemu/job.h b/include/qemu/job.h
26ba25
new file mode 100644
26ba25
index 0000000..b4b49f1
26ba25
--- /dev/null
26ba25
+++ b/include/qemu/job.h
26ba25
@@ -0,0 +1,60 @@
26ba25
+/*
26ba25
+ * Declarations for background jobs
26ba25
+ *
26ba25
+ * Copyright (c) 2011 IBM Corp.
26ba25
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
26ba25
+ *
26ba25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
26ba25
+ * of this software and associated documentation files (the "Software"), to deal
26ba25
+ * in the Software without restriction, including without limitation the rights
26ba25
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26ba25
+ * copies of the Software, and to permit persons to whom the Software is
26ba25
+ * furnished to do so, subject to the following conditions:
26ba25
+ *
26ba25
+ * The above copyright notice and this permission notice shall be included in
26ba25
+ * all copies or substantial portions of the Software.
26ba25
+ *
26ba25
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26ba25
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26ba25
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26ba25
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26ba25
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26ba25
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26ba25
+ * THE SOFTWARE.
26ba25
+ */
26ba25
+
26ba25
+#ifndef JOB_H
26ba25
+#define JOB_H
26ba25
+
26ba25
+typedef struct JobDriver JobDriver;
26ba25
+
26ba25
+/**
26ba25
+ * Long-running operation.
26ba25
+ */
26ba25
+typedef struct Job {
26ba25
+    /** The ID of the job. May be NULL for internal jobs. */
26ba25
+    char *id;
26ba25
+
26ba25
+    /** The type of this job. */
26ba25
+    const JobDriver *driver;
26ba25
+} Job;
26ba25
+
26ba25
+/**
26ba25
+ * Callbacks and other information about a Job driver.
26ba25
+ */
26ba25
+struct JobDriver {
26ba25
+    /** Derived Job struct size */
26ba25
+    size_t instance_size;
26ba25
+};
26ba25
+
26ba25
+
26ba25
+/**
26ba25
+ * Create a new long-running job and return it.
26ba25
+ *
26ba25
+ * @job_id: The id of the newly-created job, or %NULL for internal jobs
26ba25
+ * @driver: The class object for the newly-created job.
26ba25
+ * @errp: Error object.
26ba25
+ */
26ba25
+void *job_create(const char *job_id, const JobDriver *driver, Error **errp);
26ba25
+
26ba25
+#endif
26ba25
diff --git a/job.c b/job.c
26ba25
new file mode 100644
26ba25
index 0000000..87fd484
26ba25
--- /dev/null
26ba25
+++ b/job.c
26ba25
@@ -0,0 +1,48 @@
26ba25
+/*
26ba25
+ * Background jobs (long-running operations)
26ba25
+ *
26ba25
+ * Copyright (c) 2011 IBM Corp.
26ba25
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
26ba25
+ *
26ba25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
26ba25
+ * of this software and associated documentation files (the "Software"), to deal
26ba25
+ * in the Software without restriction, including without limitation the rights
26ba25
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26ba25
+ * copies of the Software, and to permit persons to whom the Software is
26ba25
+ * furnished to do so, subject to the following conditions:
26ba25
+ *
26ba25
+ * The above copyright notice and this permission notice shall be included in
26ba25
+ * all copies or substantial portions of the Software.
26ba25
+ *
26ba25
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26ba25
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26ba25
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26ba25
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26ba25
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26ba25
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26ba25
+ * THE SOFTWARE.
26ba25
+ */
26ba25
+
26ba25
+#include "qemu/osdep.h"
26ba25
+#include "qemu-common.h"
26ba25
+#include "qapi/error.h"
26ba25
+#include "qemu/job.h"
26ba25
+#include "qemu/id.h"
26ba25
+
26ba25
+void *job_create(const char *job_id, const JobDriver *driver, Error **errp)
26ba25
+{
26ba25
+    Job *job;
26ba25
+
26ba25
+    if (job_id) {
26ba25
+        if (!id_wellformed(job_id)) {
26ba25
+            error_setg(errp, "Invalid job ID '%s'", job_id);
26ba25
+            return NULL;
26ba25
+        }
26ba25
+    }
26ba25
+
26ba25
+    job = g_malloc0(driver->instance_size);
26ba25
+    job->driver        = driver;
26ba25
+    job->id            = g_strdup(job_id);
26ba25
+
26ba25
+    return job;
26ba25
+}
26ba25
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
26ba25
index 7673de1..fe9f412 100644
26ba25
--- a/tests/test-bdrv-drain.c
26ba25
+++ b/tests/test-bdrv-drain.c
26ba25
@@ -520,7 +520,9 @@ static void test_job_complete(BlockJob *job, Error **errp)
26ba25
 }
26ba25
 
26ba25
 BlockJobDriver test_job_driver = {
26ba25
-    .instance_size  = sizeof(TestBlockJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size  = sizeof(TestBlockJob),
26ba25
+    },
26ba25
     .start          = test_job_start,
26ba25
     .complete       = test_job_complete,
26ba25
 };
26ba25
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
26ba25
index 5789893..48b12d1 100644
26ba25
--- a/tests/test-blockjob-txn.c
26ba25
+++ b/tests/test-blockjob-txn.c
26ba25
@@ -74,7 +74,9 @@ static void test_block_job_cb(void *opaque, int ret)
26ba25
 }
26ba25
 
26ba25
 static const BlockJobDriver test_block_job_driver = {
26ba25
-    .instance_size = sizeof(TestBlockJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size = sizeof(TestBlockJob),
26ba25
+    },
26ba25
     .start = test_block_job_run,
26ba25
 };
26ba25
 
26ba25
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
26ba25
index 8946bfd..b820261 100644
26ba25
--- a/tests/test-blockjob.c
26ba25
+++ b/tests/test-blockjob.c
26ba25
@@ -17,7 +17,9 @@
26ba25
 #include "sysemu/block-backend.h"
26ba25
 
26ba25
 static const BlockJobDriver test_block_job_driver = {
26ba25
-    .instance_size = sizeof(BlockJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size = sizeof(BlockJob),
26ba25
+    },
26ba25
 };
26ba25
 
26ba25
 static void block_job_cb(void *opaque, int ret)
26ba25
@@ -38,9 +40,9 @@ static BlockJob *mk_job(BlockBackend *blk, const char *id,
26ba25
         g_assert_null(errp);
26ba25
         g_assert_nonnull(job);
26ba25
         if (id) {
26ba25
-            g_assert_cmpstr(job->id, ==, id);
26ba25
+            g_assert_cmpstr(job->job.id, ==, id);
26ba25
         } else {
26ba25
-            g_assert_cmpstr(job->id, ==, blk_name(blk));
26ba25
+            g_assert_cmpstr(job->job.id, ==, blk_name(blk));
26ba25
         }
26ba25
     } else {
26ba25
         g_assert_nonnull(errp);
26ba25
@@ -192,7 +194,9 @@ static void coroutine_fn cancel_job_start(void *opaque)
26ba25
 }
26ba25
 
26ba25
 static const BlockJobDriver test_cancel_driver = {
26ba25
-    .instance_size = sizeof(CancelJob),
26ba25
+    .job_driver = {
26ba25
+        .instance_size = sizeof(CancelJob),
26ba25
+    },
26ba25
     .start         = cancel_job_start,
26ba25
     .complete      = cancel_job_complete,
26ba25
 };
26ba25
-- 
26ba25
1.8.3.1
26ba25