aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS2
-rw-r--r--Makefile.objs2
-rw-r--r--block/backup.c4
-rw-r--r--block/commit.c4
-rw-r--r--block/mirror.c10
-rw-r--r--block/stream.c4
-rw-r--r--blockjob.c46
-rw-r--r--include/block/blockjob.h9
-rw-r--r--include/block/blockjob_int.h4
-rw-r--r--include/qemu/job.h60
-rw-r--r--job.c48
-rw-r--r--tests/test-bdrv-drain.c4
-rw-r--r--tests/test-blockjob-txn.c4
-rw-r--r--tests/test-blockjob.c12
14 files changed, 169 insertions, 44 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index e187b1f18f..9fba3307d9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1369,6 +1369,8 @@ L: qemu-block@nongnu.org
S: Supported
F: blockjob.c
F: include/block/blockjob.h
+F: job.c
+F: include/block/job.h
F: block/backup.c
F: block/commit.c
F: block/stream.c
diff --git a/Makefile.objs b/Makefile.objs
index c6c9b8fc21..92b73fc272 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -63,7 +63,7 @@ chardev-obj-y = chardev/
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y += nbd/
-block-obj-y += block.o blockjob.o
+block-obj-y += block.o blockjob.o job.o
block-obj-y += block/ scsi/
block-obj-y += qemu-io-cmds.o
block-obj-$(CONFIG_REPLICATION) += replication.o
diff --git a/block/backup.c b/block/backup.c
index e14d99560d..9e672bbd5e 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -523,7 +523,9 @@ static void coroutine_fn backup_run(void *opaque)
}
static const BlockJobDriver backup_job_driver = {
- .instance_size = sizeof(BackupBlockJob),
+ .job_driver = {
+ .instance_size = sizeof(BackupBlockJob),
+ },
.job_type = BLOCK_JOB_TYPE_BACKUP,
.start = backup_run,
.commit = backup_commit,
diff --git a/block/commit.c b/block/commit.c
index ba5df6aa0a..18cbb2f9c4 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -215,7 +215,9 @@ out:
}
static const BlockJobDriver commit_job_driver = {
- .instance_size = sizeof(CommitBlockJob),
+ .job_driver = {
+ .instance_size = sizeof(CommitBlockJob),
+ },
.job_type = BLOCK_JOB_TYPE_COMMIT,
.start = commit_run,
};
diff --git a/block/mirror.c b/block/mirror.c
index a4197bb975..aa1d6b742e 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -913,7 +913,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
if (!s->synced) {
error_setg(errp, "The active block job '%s' cannot be completed",
- job->id);
+ job->job.id);
return;
}
@@ -986,7 +986,9 @@ static void mirror_drain(BlockJob *job)
}
static const BlockJobDriver mirror_job_driver = {
- .instance_size = sizeof(MirrorBlockJob),
+ .job_driver = {
+ .instance_size = sizeof(MirrorBlockJob),
+ },
.job_type = BLOCK_JOB_TYPE_MIRROR,
.start = mirror_run,
.complete = mirror_complete,
@@ -996,7 +998,9 @@ static const BlockJobDriver mirror_job_driver = {
};
static const BlockJobDriver commit_active_job_driver = {
- .instance_size = sizeof(MirrorBlockJob),
+ .job_driver = {
+ .instance_size = sizeof(MirrorBlockJob),
+ },
.job_type = BLOCK_JOB_TYPE_COMMIT,
.start = mirror_run,
.complete = mirror_complete,
diff --git a/block/stream.c b/block/stream.c
index df9660d2fc..f88fc75141 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -209,7 +209,9 @@ out:
}
static const BlockJobDriver stream_job_driver = {
- .instance_size = sizeof(StreamBlockJob),
+ .job_driver = {
+ .instance_size = sizeof(StreamBlockJob),
+ },
.job_type = BLOCK_JOB_TYPE_STREAM,
.start = stream_run,
};
diff --git a/blockjob.c b/blockjob.c
index 112672a68b..1464856eb5 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -34,7 +34,6 @@
#include "qapi/qapi-events-block-core.h"
#include "qapi/qmp/qerror.h"
#include "qemu/coroutine.h"
-#include "qemu/id.h"
#include "qemu/timer.h"
/* Right now, this mutex is only needed to synchronize accesses to job->busy
@@ -92,7 +91,8 @@ static int block_job_apply_verb(BlockJob *job, BlockJobVerb bv, Error **errp)
return 0;
}
error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'",
- job->id, BlockJobStatus_str(job->status), BlockJobVerb_str(bv));
+ job->job.id, BlockJobStatus_str(job->status),
+ BlockJobVerb_str(bv));
return -EPERM;
}
@@ -159,7 +159,7 @@ BlockJob *block_job_get(const char *id)
BlockJob *job;
QLIST_FOREACH(job, &block_jobs, job_list) {
- if (job->id && !strcmp(id, job->id)) {
+ if (job->job.id && !strcmp(id, job->job.id)) {
return job;
}
}
@@ -261,7 +261,7 @@ void block_job_unref(BlockJob *job)
block_job_detach_aio_context, job);
blk_unref(job->blk);
error_free(job->blocker);
- g_free(job->id);
+ g_free(job->job.id);
assert(!timer_pending(&job->sleep_timer));
g_free(job);
}
@@ -311,7 +311,7 @@ static char *child_job_get_parent_desc(BdrvChild *c)
BlockJob *job = c->opaque;
return g_strdup_printf("%s job '%s'",
BlockJobType_str(job->driver->job_type),
- job->id);
+ job->job.id);
}
static void child_job_drained_begin(BdrvChild *c)
@@ -365,7 +365,7 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
bool block_job_is_internal(BlockJob *job)
{
- return (job->id == NULL);
+ return (job->job.id == NULL);
}
static bool block_job_started(BlockJob *job)
@@ -705,13 +705,13 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n)
void block_job_complete(BlockJob *job, Error **errp)
{
/* Should not be reachable via external interface for internal jobs */
- assert(job->id);
+ assert(job->job.id);
if (block_job_apply_verb(job, BLOCK_JOB_VERB_COMPLETE, errp)) {
return;
}
if (job->pause_count || job->cancelled || !job->driver->complete) {
error_setg(errp, "The active block job '%s' cannot be completed",
- job->id);
+ job->job.id);
return;
}
@@ -720,7 +720,7 @@ void block_job_complete(BlockJob *job, Error **errp)
void block_job_finalize(BlockJob *job, Error **errp)
{
- assert(job && job->id);
+ assert(job && job->job.id);
if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) {
return;
}
@@ -731,7 +731,7 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp)
{
BlockJob *job = *jobptr;
/* similarly to _complete, this is QMP-interface only. */
- assert(job->id);
+ assert(job->job.id);
if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) {
return;
}
@@ -848,7 +848,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
}
info = g_new0(BlockJobInfo, 1);
info->type = g_strdup(BlockJobType_str(job->driver->job_type));
- info->device = g_strdup(job->id);
+ info->device = g_strdup(job->job.id);
info->len = job->len;
info->busy = atomic_read(&job->busy);
info->paused = job->pause_count > 0;
@@ -879,7 +879,7 @@ static void block_job_event_cancelled(BlockJob *job)
}
qapi_event_send_block_job_cancelled(job->driver->job_type,
- job->id,
+ job->job.id,
job->len,
job->offset,
job->speed,
@@ -893,7 +893,7 @@ static void block_job_event_completed(BlockJob *job, const char *msg)
}
qapi_event_send_block_job_completed(job->driver->job_type,
- job->id,
+ job->job.id,
job->len,
job->offset,
job->speed,
@@ -907,7 +907,7 @@ static int block_job_event_pending(BlockJob *job)
block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING);
if (!job->auto_finalize && !block_job_is_internal(job)) {
qapi_event_send_block_job_pending(job->driver->job_type,
- job->id,
+ job->job.id,
&error_abort);
}
return 0;
@@ -945,12 +945,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
error_setg(errp, "Cannot specify job ID for internal block job");
return NULL;
}
-
- if (!id_wellformed(job_id)) {
- error_setg(errp, "Invalid job ID '%s'", job_id);
- return NULL;
- }
-
if (block_job_get(job_id)) {
error_setg(errp, "Job ID '%s' already in use", job_id);
return NULL;
@@ -964,9 +958,13 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
return NULL;
}
- job = g_malloc0(driver->instance_size);
+ job = job_create(job_id, &driver->job_driver, errp);
+ if (job == NULL) {
+ blk_unref(blk);
+ return NULL;
+ }
+
job->driver = driver;
- job->id = g_strdup(job_id);
job->blk = blk;
job->cb = cb;
job->opaque = opaque;
@@ -1187,7 +1185,7 @@ void block_job_event_ready(BlockJob *job)
}
qapi_event_send_block_job_ready(job->driver->job_type,
- job->id,
+ job->job.id,
job->len,
job->offset,
job->speed, &error_abort);
@@ -1217,7 +1215,7 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
abort();
}
if (!block_job_is_internal(job)) {
- qapi_event_send_block_job_error(job->id,
+ qapi_event_send_block_job_error(job->job.id,
is_read ? IO_OPERATION_TYPE_READ :
IO_OPERATION_TYPE_WRITE,
action, &error_abort);
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index 0f56f723de..640e649034 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -26,6 +26,7 @@
#ifndef BLOCKJOB_H
#define BLOCKJOB_H
+#include "qemu/job.h"
#include "block/block.h"
#include "qemu/ratelimit.h"
@@ -40,6 +41,9 @@ typedef struct BlockJobTxn BlockJobTxn;
* Long-running operation on a BlockDriverState.
*/
typedef struct BlockJob {
+ /** Data belonging to the generic Job infrastructure */
+ Job job;
+
/** The job type, including the job vtable. */
const BlockJobDriver *driver;
@@ -47,11 +51,6 @@ typedef struct BlockJob {
BlockBackend *blk;
/**
- * The ID of the block job. May be NULL for internal jobs.
- */
- char *id;
-
- /**
* The coroutine that executes the job. If not NULL, it is
* reentered when busy is false and the job is cancelled.
*/
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
index 62ec964d09..e8eca44747 100644
--- a/include/block/blockjob_int.h
+++ b/include/block/blockjob_int.h
@@ -35,8 +35,8 @@
* A class type for block job driver.
*/
struct BlockJobDriver {
- /** Derived BlockJob struct size */
- size_t instance_size;
+ /** Generic JobDriver callbacks and settings */
+ JobDriver job_driver;
/** String describing the operation, part of query-block-jobs QMP API */
BlockJobType job_type;
diff --git a/include/qemu/job.h b/include/qemu/job.h
new file mode 100644
index 0000000000..b4b49f19e1
--- /dev/null
+++ b/include/qemu/job.h
@@ -0,0 +1,60 @@
+/*
+ * Declarations for background jobs
+ *
+ * Copyright (c) 2011 IBM Corp.
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef JOB_H
+#define JOB_H
+
+typedef struct JobDriver JobDriver;
+
+/**
+ * Long-running operation.
+ */
+typedef struct Job {
+ /** The ID of the job. May be NULL for internal jobs. */
+ char *id;
+
+ /** The type of this job. */
+ const JobDriver *driver;
+} Job;
+
+/**
+ * Callbacks and other information about a Job driver.
+ */
+struct JobDriver {
+ /** Derived Job struct size */
+ size_t instance_size;
+};
+
+
+/**
+ * Create a new long-running job and return it.
+ *
+ * @job_id: The id of the newly-created job, or %NULL for internal jobs
+ * @driver: The class object for the newly-created job.
+ * @errp: Error object.
+ */
+void *job_create(const char *job_id, const JobDriver *driver, Error **errp);
+
+#endif
diff --git a/job.c b/job.c
new file mode 100644
index 0000000000..87fd48468c
--- /dev/null
+++ b/job.c
@@ -0,0 +1,48 @@
+/*
+ * Background jobs (long-running operations)
+ *
+ * Copyright (c) 2011 IBM Corp.
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qemu/job.h"
+#include "qemu/id.h"
+
+void *job_create(const char *job_id, const JobDriver *driver, Error **errp)
+{
+ Job *job;
+
+ if (job_id) {
+ if (!id_wellformed(job_id)) {
+ error_setg(errp, "Invalid job ID '%s'", job_id);
+ return NULL;
+ }
+ }
+
+ job = g_malloc0(driver->instance_size);
+ job->driver = driver;
+ job->id = g_strdup(job_id);
+
+ return job;
+}
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
index 7673de1062..fe9f412b39 100644
--- a/tests/test-bdrv-drain.c
+++ b/tests/test-bdrv-drain.c
@@ -520,7 +520,9 @@ static void test_job_complete(BlockJob *job, Error **errp)
}
BlockJobDriver test_job_driver = {
- .instance_size = sizeof(TestBlockJob),
+ .job_driver = {
+ .instance_size = sizeof(TestBlockJob),
+ },
.start = test_job_start,
.complete = test_job_complete,
};
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
index 5789893dda..48b12d1744 100644
--- a/tests/test-blockjob-txn.c
+++ b/tests/test-blockjob-txn.c
@@ -74,7 +74,9 @@ static void test_block_job_cb(void *opaque, int ret)
}
static const BlockJobDriver test_block_job_driver = {
- .instance_size = sizeof(TestBlockJob),
+ .job_driver = {
+ .instance_size = sizeof(TestBlockJob),
+ },
.start = test_block_job_run,
};
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
index 8946bfd37b..b82026180a 100644
--- a/tests/test-blockjob.c
+++ b/tests/test-blockjob.c
@@ -17,7 +17,9 @@
#include "sysemu/block-backend.h"
static const BlockJobDriver test_block_job_driver = {
- .instance_size = sizeof(BlockJob),
+ .job_driver = {
+ .instance_size = sizeof(BlockJob),
+ },
};
static void block_job_cb(void *opaque, int ret)
@@ -38,9 +40,9 @@ static BlockJob *mk_job(BlockBackend *blk, const char *id,
g_assert_null(errp);
g_assert_nonnull(job);
if (id) {
- g_assert_cmpstr(job->id, ==, id);
+ g_assert_cmpstr(job->job.id, ==, id);
} else {
- g_assert_cmpstr(job->id, ==, blk_name(blk));
+ g_assert_cmpstr(job->job.id, ==, blk_name(blk));
}
} else {
g_assert_nonnull(errp);
@@ -192,7 +194,9 @@ static void coroutine_fn cancel_job_start(void *opaque)
}
static const BlockJobDriver test_cancel_driver = {
- .instance_size = sizeof(CancelJob),
+ .job_driver = {
+ .instance_size = sizeof(CancelJob),
+ },
.start = cancel_job_start,
.complete = cancel_job_complete,
};