#include "qemu/main-loop.h"
#include "block/blockjob_int.h"
#include "sysemu/block-backend.h"
+#include "qapi/qmp/qdict.h"
static const BlockJobDriver test_block_job_driver = {
- .instance_size = sizeof(BlockJob),
+ .job_driver = {
+ .instance_size = sizeof(BlockJob),
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ },
};
static void block_job_cb(void *opaque, int ret)
int flags)
{
BlockJob *job;
- Error *errp = NULL;
+ Error *err = NULL;
job = block_job_create(id, drv, NULL, blk_bs(blk),
0, BLK_PERM_ALL, 0, flags, block_job_cb,
- NULL, &errp);
+ NULL, &err);
if (should_succeed) {
- g_assert_null(errp);
+ g_assert_null(err);
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);
+ error_free_or_abort(&err);
g_assert_null(job);
- error_free(errp);
}
return job;
bool should_succeed)
{
return mk_job(blk, id, &test_block_job_driver,
- should_succeed, BLOCK_JOB_DEFAULT);
+ should_succeed, JOB_DEFAULT);
}
/* This creates a BlockBackend (optionally with a name) with a
static BlockBackend *create_blk(const char *name)
{
/* No I/O is performed on this device */
- BlockBackend *blk = blk_new(0, BLK_PERM_ALL);
+ BlockBackend *blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
BlockDriverState *bs;
- bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
+ QDict *opt = qdict_new();
+ qdict_put_str(opt, "file.read-zeroes", "on");
+ bs = bdrv_open("null-co://", NULL, opt, 0, &error_abort);
g_assert_nonnull(bs);
blk_insert_bs(blk, bs, &error_abort);
bdrv_unref(bs);
if (name) {
- Error *errp = NULL;
- monitor_add_blk(blk, name, &errp);
- g_assert_null(errp);
+ Error *err = NULL;
+ monitor_add_blk(blk, name, &err);
+ g_assert_null(err);
}
return blk;
/* This one is valid */
job[0] = do_test_id(blk[0], "id0", true);
- /* We cannot have two jobs in the same BDS */
- do_test_id(blk[0], "id1", false);
+ /* We can have two jobs in the same BDS */
+ job[1] = do_test_id(blk[0], "id1", true);
+ job_early_fail(&job[1]->job);
/* Duplicate job IDs are not allowed */
job[1] = do_test_id(blk[1], "id0", false);
/* But once job[0] finishes we can reuse its ID */
- block_job_early_fail(job[0]);
+ job_early_fail(&job[0]->job);
job[1] = do_test_id(blk[1], "id0", true);
/* No job ID specified, defaults to the backend name ('drive1') */
- block_job_early_fail(job[1]);
+ job_early_fail(&job[1]->job);
job[1] = do_test_id(blk[1], NULL, true);
/* Duplicate job ID */
/* This one is valid */
job[2] = do_test_id(blk[2], "id_2", true);
- block_job_early_fail(job[0]);
- block_job_early_fail(job[1]);
- block_job_early_fail(job[2]);
+ job_early_fail(&job[0]->job);
+ job_early_fail(&job[1]->job);
+ job_early_fail(&job[2]->job);
destroy_blk(blk[0]);
destroy_blk(blk[1]);
BlockBackend *blk;
bool should_converge;
bool should_complete;
- bool completed;
} CancelJob;
-static void cancel_job_completed(BlockJob *job, void *opaque)
+static void cancel_job_complete(Job *job, Error **errp)
{
- CancelJob *s = opaque;
- s->completed = true;
- block_job_completed(job, 0);
-}
-
-static void cancel_job_complete(BlockJob *job, Error **errp)
-{
- CancelJob *s = container_of(job, CancelJob, common);
+ CancelJob *s = container_of(job, CancelJob, common.job);
s->should_complete = true;
}
-static void coroutine_fn cancel_job_start(void *opaque)
+static int coroutine_fn cancel_job_run(Job *job, Error **errp)
{
- CancelJob *s = opaque;
+ CancelJob *s = container_of(job, CancelJob, common.job);
while (!s->should_complete) {
- if (block_job_is_cancelled(&s->common)) {
- goto defer;
+ if (job_is_cancelled(&s->common.job)) {
+ return 0;
}
- if (!s->common.ready && s->should_converge) {
- block_job_event_ready(&s->common);
+ if (!job_is_ready(&s->common.job) && s->should_converge) {
+ job_transition_to_ready(&s->common.job);
}
- block_job_sleep_ns(&s->common, 100000);
+ job_sleep_ns(&s->common.job, 100000);
}
- defer:
- block_job_defer_to_main_loop(&s->common, cancel_job_completed, s);
+ return 0;
}
static const BlockJobDriver test_cancel_driver = {
- .instance_size = sizeof(CancelJob),
- .start = cancel_job_start,
- .complete = cancel_job_complete,
+ .job_driver = {
+ .instance_size = sizeof(CancelJob),
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .run = cancel_job_run,
+ .complete = cancel_job_complete,
+ },
};
-static CancelJob *create_common(BlockJob **pjob)
+static CancelJob *create_common(Job **pjob)
{
BlockBackend *blk;
- BlockJob *job;
+ Job *job;
+ BlockJob *bjob;
CancelJob *s;
blk = create_blk(NULL);
- job = mk_job(blk, "Steve", &test_cancel_driver, true,
- BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS);
- block_job_ref(job);
- assert(job->status == BLOCK_JOB_STATUS_CREATED);
- s = container_of(job, CancelJob, common);
+ bjob = mk_job(blk, "Steve", &test_cancel_driver, true,
+ JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS);
+ job = &bjob->job;
+ job_ref(job);
+ assert(job->status == JOB_STATUS_CREATED);
+ s = container_of(bjob, CancelJob, common);
s->blk = blk;
*pjob = job;
{
BlockJob *job = &s->common;
BlockBackend *blk = s->blk;
- BlockJobStatus sts = job->status;
+ JobStatus sts = job->job.status;
+ AioContext *ctx;
- block_job_cancel_sync(job);
- if ((sts != BLOCK_JOB_STATUS_CREATED) &&
- (sts != BLOCK_JOB_STATUS_CONCLUDED)) {
- BlockJob *dummy = job;
- block_job_dismiss(&dummy, &error_abort);
+ ctx = job->job.aio_context;
+ aio_context_acquire(ctx);
+
+ job_cancel_sync(&job->job);
+ if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) {
+ Job *dummy = &job->job;
+ job_dismiss(&dummy, &error_abort);
}
- assert(job->status == BLOCK_JOB_STATUS_NULL);
- block_job_unref(job);
+ assert(job->job.status == JOB_STATUS_NULL);
+ job_unref(&job->job);
destroy_blk(blk);
+
+ aio_context_release(ctx);
}
static void test_cancel_created(void)
{
- BlockJob *job;
+ Job *job;
CancelJob *s;
s = create_common(&job);
static void test_cancel_running(void)
{
- BlockJob *job;
+ Job *job;
CancelJob *s;
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(job);
+ assert(job->status == JOB_STATUS_RUNNING);
cancel_common(s);
}
static void test_cancel_paused(void)
{
- BlockJob *job;
+ Job *job;
CancelJob *s;
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(job);
+ assert(job->status == JOB_STATUS_RUNNING);
- block_job_user_pause(job, &error_abort);
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_PAUSED);
+ job_user_pause(job, &error_abort);
+ job_enter(job);
+ assert(job->status == JOB_STATUS_PAUSED);
cancel_common(s);
}
static void test_cancel_ready(void)
{
- BlockJob *job;
+ Job *job;
CancelJob *s;
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(job);
+ assert(job->status == JOB_STATUS_RUNNING);
s->should_converge = true;
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_READY);
+ job_enter(job);
+ assert(job->status == JOB_STATUS_READY);
cancel_common(s);
}
static void test_cancel_standby(void)
{
- BlockJob *job;
+ Job *job;
CancelJob *s;
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(job);
+ assert(job->status == JOB_STATUS_RUNNING);
s->should_converge = true;
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_READY);
+ job_enter(job);
+ assert(job->status == JOB_STATUS_READY);
- block_job_user_pause(job, &error_abort);
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_STANDBY);
+ job_user_pause(job, &error_abort);
+ job_enter(job);
+ assert(job->status == JOB_STATUS_STANDBY);
cancel_common(s);
}
static void test_cancel_pending(void)
{
- BlockJob *job;
+ Job *job;
CancelJob *s;
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(job);
+ assert(job->status == JOB_STATUS_RUNNING);
s->should_converge = true;
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_READY);
+ job_enter(job);
+ assert(job->status == JOB_STATUS_READY);
- block_job_complete(job, &error_abort);
- block_job_enter(job);
- while (!s->completed) {
+ job_complete(job, &error_abort);
+ job_enter(job);
+ while (!job->deferred_to_main_loop) {
aio_poll(qemu_get_aio_context(), true);
}
- assert(job->status == BLOCK_JOB_STATUS_PENDING);
+ assert(job->status == JOB_STATUS_READY);
+ aio_poll(qemu_get_aio_context(), true);
+ assert(job->status == JOB_STATUS_PENDING);
cancel_common(s);
}
static void test_cancel_concluded(void)
{
- BlockJob *job;
+ Job *job;
CancelJob *s;
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(job);
+ assert(job->status == JOB_STATUS_RUNNING);
s->should_converge = true;
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_READY);
+ job_enter(job);
+ assert(job->status == JOB_STATUS_READY);
- block_job_complete(job, &error_abort);
- block_job_enter(job);
- while (!s->completed) {
+ job_complete(job, &error_abort);
+ job_enter(job);
+ while (!job->deferred_to_main_loop) {
aio_poll(qemu_get_aio_context(), true);
}
- assert(job->status == BLOCK_JOB_STATUS_PENDING);
-
- block_job_finalize(job, &error_abort);
- assert(job->status == BLOCK_JOB_STATUS_CONCLUDED);
+ assert(job->status == JOB_STATUS_READY);
+ aio_poll(qemu_get_aio_context(), true);
+ assert(job->status == JOB_STATUS_PENDING);
+
+ aio_context_acquire(job->aio_context);
+ job_finalize(job, &error_abort);
+ aio_context_release(job->aio_context);
+ assert(job->status == JOB_STATUS_CONCLUDED);
cancel_common(s);
}