From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524583951481222.75035268497095; Tue, 24 Apr 2018 08:32:31 -0700 (PDT) Received: from localhost ([::1]:59120 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzvi-0004vQ-Is for importer@patchew.org; Tue, 24 Apr 2018 11:32:30 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47433) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzow-0007hW-Ll for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzou-0007be-Ii for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:30 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57158 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzoq-0007U5-7C; Tue, 24 Apr 2018 11:25:24 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D072F81A88BE; Tue, 24 Apr 2018 15:25:23 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id C065F2026990; Tue, 24 Apr 2018 15:25:22 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:43 +0200 Message-Id: <20180424152515.25664-2-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 24 Apr 2018 15:25:23 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 24 Apr 2018 15:25:23 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 01/33] blockjob: Wrappers for progress counter access X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Block job drivers are not expected to mess with the internal of the BlockJob object, so provide wrapper functions for one of the cases where they still do it: Updating the progress counter. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- include/block/blockjob.h | 19 +++++++++++++++++++ block/backup.c | 22 +++++++++++++--------- block/commit.c | 16 ++++++++-------- block/mirror.c | 11 +++++------ block/stream.c | 14 ++++++++------ blockjob.c | 10 ++++++++++ 6 files changed, 63 insertions(+), 29 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index fc645dac68..a2cc52233b 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -278,6 +278,25 @@ void block_job_finalize(BlockJob *job, Error **errp); void block_job_dismiss(BlockJob **job, Error **errp); =20 /** + * block_job_progress_update: + * @job: The job that has made progress + * @done: How much progress the job made + * + * Updates the progress counter of the job. + */ +void block_job_progress_update(BlockJob *job, uint64_t done); + +/** + * block_job_progress_set_remaining: + * @job: The job whose expected progress end value is set + * @remaining: Expected end value of the progress counter of the job + * + * Sets the expected end value of the progress counter of a job so that a + * completion percentage can be calculated when the progress is updated. + */ +void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining); + +/** * block_job_query: * @job: The job to get information about. * diff --git a/block/backup.c b/block/backup.c index 453cd62c24..5d95805472 100644 --- a/block/backup.c +++ b/block/backup.c @@ -39,6 +39,7 @@ typedef struct BackupBlockJob { BlockdevOnError on_source_error; BlockdevOnError on_target_error; CoRwlock flush_rwlock; + uint64_t len; uint64_t bytes_read; int64_t cluster_size; bool compress; @@ -118,7 +119,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *j= ob, =20 trace_backup_do_cow_process(job, start); =20 - n =3D MIN(job->cluster_size, job->common.len - start); + n =3D MIN(job->cluster_size, job->len - start); =20 if (!bounce_buffer) { bounce_buffer =3D blk_blockalign(blk, job->cluster_size); @@ -159,7 +160,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *j= ob, * offset field is an opaque progress value, it is not a disk offs= et. */ job->bytes_read +=3D n; - job->common.offset +=3D n; + block_job_progress_update(&job->common, n); } =20 out: @@ -261,7 +262,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp) return; } =20 - len =3D DIV_ROUND_UP(backup_job->common.len, backup_job->cluster_size); + len =3D DIV_ROUND_UP(backup_job->len, backup_job->cluster_size); hbitmap_set(backup_job->copy_bitmap, 0, len); } =20 @@ -420,8 +421,9 @@ static void backup_incremental_init_copy_bitmap(BackupB= lockJob *job) bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size); } =20 - job->common.offset =3D job->common.len - - hbitmap_count(job->copy_bitmap) * job->cluster_si= ze; + /* TODO block_job_progress_set_remaining() would make more sense */ + block_job_progress_update(&job->common, + job->len - hbitmap_count(job->copy_bitmap) * job->cluster_size); =20 bdrv_dirty_iter_free(dbi); } @@ -437,7 +439,9 @@ static void coroutine_fn backup_run(void *opaque) QLIST_INIT(&job->inflight_reqs); qemu_co_rwlock_init(&job->flush_rwlock); =20 - nb_clusters =3D DIV_ROUND_UP(job->common.len, job->cluster_size); + nb_clusters =3D DIV_ROUND_UP(job->len, job->cluster_size); + block_job_progress_set_remaining(&job->common, job->len); + job->copy_bitmap =3D hbitmap_alloc(nb_clusters, 0); if (job->sync_mode =3D=3D MIRROR_SYNC_MODE_INCREMENTAL) { backup_incremental_init_copy_bitmap(job); @@ -461,7 +465,7 @@ static void coroutine_fn backup_run(void *opaque) ret =3D backup_run_incremental(job); } else { /* Both FULL and TOP SYNC_MODE's require copying.. */ - for (offset =3D 0; offset < job->common.len; + for (offset =3D 0; offset < job->len; offset +=3D job->cluster_size) { bool error_is_read; int alloced =3D 0; @@ -620,7 +624,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDr= iverState *bs, goto error; } =20 - /* job->common.len is fixed, so we can't allow resize */ + /* job->len is fixed, so we can't allow resize */ job =3D block_job_create(job_id, &backup_job_driver, txn, bs, BLK_PERM_CONSISTENT_READ, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | @@ -676,7 +680,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDr= iverState *bs, /* Required permissions are already taken with target's blk_new() */ block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, &error_abort); - job->common.len =3D len; + job->len =3D len; =20 return &job->common; =20 diff --git a/block/commit.c b/block/commit.c index 1432baeef4..50b191c980 100644 --- a/block/commit.c +++ b/block/commit.c @@ -146,21 +146,21 @@ static void coroutine_fn commit_run(void *opaque) int64_t n =3D 0; /* bytes */ void *buf =3D NULL; int bytes_written =3D 0; - int64_t base_len; + int64_t len, base_len; =20 - ret =3D s->common.len =3D blk_getlength(s->top); - - if (s->common.len < 0) { + ret =3D len =3D blk_getlength(s->top); + if (len < 0) { goto out; } + block_job_progress_set_remaining(&s->common, len); =20 ret =3D base_len =3D blk_getlength(s->base); if (base_len < 0) { goto out; } =20 - if (base_len < s->common.len) { - ret =3D blk_truncate(s->base, s->common.len, PREALLOC_MODE_OFF, NU= LL); + if (base_len < len) { + ret =3D blk_truncate(s->base, len, PREALLOC_MODE_OFF, NULL); if (ret) { goto out; } @@ -168,7 +168,7 @@ static void coroutine_fn commit_run(void *opaque) =20 buf =3D blk_blockalign(s->top, COMMIT_BUFFER_SIZE); =20 - for (offset =3D 0; offset < s->common.len; offset +=3D n) { + for (offset =3D 0; offset < len; offset +=3D n) { bool copy; =20 /* Note that even when no rate limit is applied we need to yield @@ -198,7 +198,7 @@ static void coroutine_fn commit_run(void *opaque) } } /* Publish progress */ - s->common.offset +=3D n; + block_job_progress_update(&s->common, n); =20 if (copy && s->common.speed) { delay_ns =3D ratelimit_calculate_delay(&s->limit, n); diff --git a/block/mirror.c b/block/mirror.c index 820f512c7b..0e09e6fffb 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -121,7 +121,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret) bitmap_set(s->cow_bitmap, chunk_num, nb_chunks); } if (!s->initial_zeroing_ongoing) { - s->common.offset +=3D op->bytes; + block_job_progress_update(&s->common, op->bytes); } } qemu_iovec_destroy(&op->qiov); @@ -792,11 +792,10 @@ static void coroutine_fn mirror_run(void *opaque) block_job_pause_point(&s->common); =20 cnt =3D bdrv_get_dirty_count(s->dirty_bitmap); - /* s->common.offset contains the number of bytes already processed= so - * far, cnt is the number of dirty bytes remaining and - * s->bytes_in_flight is the number of bytes currently being - * processed; together those are the current total operation lengt= h */ - s->common.len =3D s->common.offset + s->bytes_in_flight + cnt; + /* cnt is the number of dirty bytes remaining and s->bytes_in_flig= ht is + * the number of bytes currently being processed; together those a= re + * the current total operation length */ + block_job_progress_set_remaining(&s->common, s->bytes_in_flight + = cnt); =20 /* Note that even when no rate limit is applied we need to yield * periodically with no pending I/O so that bdrv_drain_all() retur= ns. diff --git a/block/stream.c b/block/stream.c index 1a85708fcf..8369852bda 100644 --- a/block/stream.c +++ b/block/stream.c @@ -107,6 +107,7 @@ static void coroutine_fn stream_run(void *opaque) BlockBackend *blk =3D s->common.blk; BlockDriverState *bs =3D blk_bs(blk); BlockDriverState *base =3D s->base; + int64_t len; int64_t offset =3D 0; uint64_t delay_ns =3D 0; int error =3D 0; @@ -118,11 +119,12 @@ static void coroutine_fn stream_run(void *opaque) goto out; } =20 - s->common.len =3D bdrv_getlength(bs); - if (s->common.len < 0) { - ret =3D s->common.len; + len =3D bdrv_getlength(bs); + if (len < 0) { + ret =3D len; goto out; } + block_job_progress_set_remaining(&s->common, len); =20 buf =3D qemu_blockalign(bs, STREAM_BUFFER_SIZE); =20 @@ -135,7 +137,7 @@ static void coroutine_fn stream_run(void *opaque) bdrv_enable_copy_on_read(bs); } =20 - for ( ; offset < s->common.len; offset +=3D n) { + for ( ; offset < len; offset +=3D n) { bool copy; =20 /* Note that even when no rate limit is applied we need to yield @@ -159,7 +161,7 @@ static void coroutine_fn stream_run(void *opaque) =20 /* Finish early if end of backing file has been reached */ if (ret =3D=3D 0 && n =3D=3D 0) { - n =3D s->common.len - offset; + n =3D len - offset; } =20 copy =3D (ret =3D=3D 1); @@ -185,7 +187,7 @@ static void coroutine_fn stream_run(void *opaque) ret =3D 0; =20 /* Publish progress */ - s->common.offset +=3D n; + block_job_progress_update(&s->common, n); if (copy && s->common.speed) { delay_ns =3D ratelimit_calculate_delay(&s->limit, n); } else { diff --git a/blockjob.c b/blockjob.c index 27f957e571..46c8923986 100644 --- a/blockjob.c +++ b/blockjob.c @@ -810,6 +810,16 @@ int block_job_complete_sync(BlockJob *job, Error **err= p) return block_job_finish_sync(job, &block_job_complete, errp); } =20 +void block_job_progress_update(BlockJob *job, uint64_t done) +{ + job->offset +=3D done; +} + +void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining) +{ + job->len =3D job->offset + remaining; +} + BlockJobInfo *block_job_query(BlockJob *job, Error **errp) { BlockJobInfo *info; --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584523769756.162135300318; Tue, 24 Apr 2018 08:42:03 -0700 (PDT) Received: from localhost ([::1]:59179 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB04w-0003nQ-Q6 for importer@patchew.org; Tue, 24 Apr 2018 11:42:02 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47478) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzoz-0007k8-1Q for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzov-0007e6-NU for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:32 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57160 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzor-0007W8-Ho; Tue, 24 Apr 2018 11:25:25 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 29AC981A88BB; Tue, 24 Apr 2018 15:25:25 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1A319202342F; Tue, 24 Apr 2018 15:25:23 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:44 +0200 Message-Id: <20180424152515.25664-3-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 24 Apr 2018 15:25:25 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 24 Apr 2018 15:25:25 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 02/33] blockjob: Move RateLimit to BlockJob X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Every block job has a RateLimit, and they all do the exact same thing with it, so it should be common infrastructure. Move the struct field for a start. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- include/block/blockjob.h | 4 ++++ block/backup.c | 5 ++--- block/commit.c | 5 ++--- block/mirror.c | 6 +++--- block/stream.c | 5 ++--- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index a2cc52233b..22bf418209 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -27,6 +27,7 @@ #define BLOCKJOB_H =20 #include "block/block.h" +#include "qemu/ratelimit.h" =20 typedef struct BlockJobDriver BlockJobDriver; typedef struct BlockJobTxn BlockJobTxn; @@ -118,6 +119,9 @@ typedef struct BlockJob { /** Speed that was set with @block_job_set_speed. */ int64_t speed; =20 + /** Rate limiting data structure for implementing @speed. */ + RateLimit limit; + /** The completion function that will be called when the job completes= . */ BlockCompletionFunc *cb; =20 diff --git a/block/backup.c b/block/backup.c index 5d95805472..7585c4391e 100644 --- a/block/backup.c +++ b/block/backup.c @@ -35,7 +35,6 @@ typedef struct BackupBlockJob { /* bitmap for sync=3Dincremental */ BdrvDirtyBitmap *sync_bitmap; MirrorSyncMode sync_mode; - RateLimit limit; BlockdevOnError on_source_error; BlockdevOnError on_target_error; CoRwlock flush_rwlock; @@ -199,7 +198,7 @@ static void backup_set_speed(BlockJob *job, int64_t spe= ed, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER, "speed"); return; } - ratelimit_set_speed(&s->limit, speed, SLICE_TIME); + ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); } =20 static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) @@ -346,7 +345,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob= *job) * (without, VM does not reboot) */ if (job->common.speed) { - uint64_t delay_ns =3D ratelimit_calculate_delay(&job->limit, + uint64_t delay_ns =3D ratelimit_calculate_delay(&job->common.limit, job->bytes_read); job->bytes_read =3D 0; block_job_sleep_ns(&job->common, delay_ns); diff --git a/block/commit.c b/block/commit.c index 50b191c980..beec5d0ad6 100644 --- a/block/commit.c +++ b/block/commit.c @@ -35,7 +35,6 @@ enum { =20 typedef struct CommitBlockJob { BlockJob common; - RateLimit limit; BlockDriverState *commit_top_bs; BlockBackend *top; BlockBackend *base; @@ -201,7 +200,7 @@ static void coroutine_fn commit_run(void *opaque) block_job_progress_update(&s->common, n); =20 if (copy && s->common.speed) { - delay_ns =3D ratelimit_calculate_delay(&s->limit, n); + delay_ns =3D ratelimit_calculate_delay(&s->common.limit, n); } else { delay_ns =3D 0; } @@ -225,7 +224,7 @@ static void commit_set_speed(BlockJob *job, int64_t spe= ed, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER, "speed"); return; } - ratelimit_set_speed(&s->limit, speed, SLICE_TIME); + ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); } =20 static const BlockJobDriver commit_job_driver =3D { diff --git a/block/mirror.c b/block/mirror.c index 0e09e6fffb..aece2b185c 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -36,7 +36,6 @@ typedef struct MirrorBuffer { =20 typedef struct MirrorBlockJob { BlockJob common; - RateLimit limit; BlockBackend *target; BlockDriverState *mirror_top_bs; BlockDriverState *source; @@ -450,7 +449,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlo= ckJob *s) offset +=3D io_bytes; nb_chunks -=3D DIV_ROUND_UP(io_bytes, s->granularity); if (s->common.speed) { - delay_ns =3D ratelimit_calculate_delay(&s->limit, io_bytes_acc= t); + delay_ns =3D ratelimit_calculate_delay(&s->common.limit, + io_bytes_acct); } } return delay_ns; @@ -912,7 +912,7 @@ static void mirror_set_speed(BlockJob *job, int64_t spe= ed, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER, "speed"); return; } - ratelimit_set_speed(&s->limit, speed, SLICE_TIME); + ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); } =20 static void mirror_complete(BlockJob *job, Error **errp) diff --git a/block/stream.c b/block/stream.c index 8369852bda..a1d4768c2e 100644 --- a/block/stream.c +++ b/block/stream.c @@ -33,7 +33,6 @@ enum { =20 typedef struct StreamBlockJob { BlockJob common; - RateLimit limit; BlockDriverState *base; BlockdevOnError on_error; char *backing_file_str; @@ -189,7 +188,7 @@ static void coroutine_fn stream_run(void *opaque) /* Publish progress */ block_job_progress_update(&s->common, n); if (copy && s->common.speed) { - delay_ns =3D ratelimit_calculate_delay(&s->limit, n); + delay_ns =3D ratelimit_calculate_delay(&s->common.limit, n); } else { delay_ns =3D 0; } @@ -219,7 +218,7 @@ static void stream_set_speed(BlockJob *job, int64_t spe= ed, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER, "speed"); return; } - ratelimit_set_speed(&s->limit, speed, SLICE_TIME); + ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); } =20 static const BlockJobDriver stream_job_driver =3D { --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585313737795.6194951080296; Tue, 24 Apr 2018 08:55:13 -0700 (PDT) Received: from localhost ([::1]:59260 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Hg-00062O-Lu for importer@patchew.org; Tue, 24 Apr 2018 11:55:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47457) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzoy-0007j4-1Q for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzow-0007fr-LJ for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:32 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34830 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzos-0007YR-RC; Tue, 24 Apr 2018 11:25:26 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 74E91FB674; Tue, 24 Apr 2018 15:25:26 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 64C2D202323A; Tue, 24 Apr 2018 15:25:25 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:45 +0200 Message-Id: <20180424152515.25664-4-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:26 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:26 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 03/33] blockjob: Implement block_job_set_speed() centrally X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" All block job drivers support .set_speed and all of them duplicate the same code to implement it. Move that code to blockjob.c and remove the now useless callback. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- include/block/blockjob.h | 2 ++ include/block/blockjob_int.h | 3 --- block/backup.c | 13 ------------- block/commit.c | 14 -------------- block/mirror.c | 14 -------------- block/stream.c | 14 -------------- blockjob.c | 12 ++++-------- 7 files changed, 6 insertions(+), 66 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 22bf418209..5aa8a6aaec 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -29,6 +29,8 @@ #include "block/block.h" #include "qemu/ratelimit.h" =20 +#define SLICE_TIME 100000000ULL /* ns */ + typedef struct BlockJobDriver BlockJobDriver; typedef struct BlockJobTxn BlockJobTxn; =20 diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 642adce68b..870bd346a8 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -41,9 +41,6 @@ struct BlockJobDriver { /** String describing the operation, part of query-block-jobs QMP API = */ BlockJobType job_type; =20 - /** Optional callback for job types that support setting a speed limit= */ - void (*set_speed)(BlockJob *job, int64_t speed, Error **errp); - /** Mandatory: Entrypoint for the Coroutine. */ CoroutineEntry *start; =20 diff --git a/block/backup.c b/block/backup.c index 7585c4391e..8468fd9f94 100644 --- a/block/backup.c +++ b/block/backup.c @@ -27,7 +27,6 @@ #include "qemu/error-report.h" =20 #define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16) -#define SLICE_TIME 100000000ULL /* ns */ =20 typedef struct BackupBlockJob { BlockJob common; @@ -190,17 +189,6 @@ static int coroutine_fn backup_before_write_notify( return backup_do_cow(job, req->offset, req->bytes, NULL, true); } =20 -static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp) -{ - BackupBlockJob *s =3D container_of(job, BackupBlockJob, common); - - if (speed < 0) { - error_setg(errp, QERR_INVALID_PARAMETER, "speed"); - return; - } - ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); -} - static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) { BdrvDirtyBitmap *bm; @@ -540,7 +528,6 @@ static const BlockJobDriver backup_job_driver =3D { .instance_size =3D sizeof(BackupBlockJob), .job_type =3D BLOCK_JOB_TYPE_BACKUP, .start =3D backup_run, - .set_speed =3D backup_set_speed, .commit =3D backup_commit, .abort =3D backup_abort, .clean =3D backup_clean, diff --git a/block/commit.c b/block/commit.c index beec5d0ad6..46cbeaec3e 100644 --- a/block/commit.c +++ b/block/commit.c @@ -31,8 +31,6 @@ enum { COMMIT_BUFFER_SIZE =3D 512 * 1024, /* in bytes */ }; =20 -#define SLICE_TIME 100000000ULL /* ns */ - typedef struct CommitBlockJob { BlockJob common; BlockDriverState *commit_top_bs; @@ -216,21 +214,9 @@ out: block_job_defer_to_main_loop(&s->common, commit_complete, data); } =20 -static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp) -{ - CommitBlockJob *s =3D container_of(job, CommitBlockJob, common); - - if (speed < 0) { - error_setg(errp, QERR_INVALID_PARAMETER, "speed"); - return; - } - ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); -} - static const BlockJobDriver commit_job_driver =3D { .instance_size =3D sizeof(CommitBlockJob), .job_type =3D BLOCK_JOB_TYPE_COMMIT, - .set_speed =3D commit_set_speed, .start =3D commit_run, }; =20 diff --git a/block/mirror.c b/block/mirror.c index aece2b185c..de495fddc4 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -22,7 +22,6 @@ #include "qemu/ratelimit.h" #include "qemu/bitmap.h" =20 -#define SLICE_TIME 100000000ULL /* ns */ #define MAX_IN_FLIGHT 16 #define MAX_IO_BYTES (1 << 20) /* 1 Mb */ #define DEFAULT_MIRROR_BUF_SIZE (MAX_IN_FLIGHT * MAX_IO_BYTES) @@ -904,17 +903,6 @@ immediate_exit: block_job_defer_to_main_loop(&s->common, mirror_exit, data); } =20 -static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp) -{ - MirrorBlockJob *s =3D container_of(job, MirrorBlockJob, common); - - if (speed < 0) { - error_setg(errp, QERR_INVALID_PARAMETER, "speed"); - return; - } - ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); -} - static void mirror_complete(BlockJob *job, Error **errp) { MirrorBlockJob *s =3D container_of(job, MirrorBlockJob, common); @@ -999,7 +987,6 @@ static void mirror_drain(BlockJob *job) static const BlockJobDriver mirror_job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), .job_type =3D BLOCK_JOB_TYPE_MIRROR, - .set_speed =3D mirror_set_speed, .start =3D mirror_run, .complete =3D mirror_complete, .pause =3D mirror_pause, @@ -1010,7 +997,6 @@ static const BlockJobDriver mirror_job_driver =3D { static const BlockJobDriver commit_active_job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), .job_type =3D BLOCK_JOB_TYPE_COMMIT, - .set_speed =3D mirror_set_speed, .start =3D mirror_run, .complete =3D mirror_complete, .pause =3D mirror_pause, diff --git a/block/stream.c b/block/stream.c index a1d4768c2e..797d7c4f21 100644 --- a/block/stream.c +++ b/block/stream.c @@ -29,8 +29,6 @@ enum { STREAM_BUFFER_SIZE =3D 512 * 1024, /* in bytes */ }; =20 -#define SLICE_TIME 100000000ULL /* ns */ - typedef struct StreamBlockJob { BlockJob common; BlockDriverState *base; @@ -210,21 +208,9 @@ out: block_job_defer_to_main_loop(&s->common, stream_complete, data); } =20 -static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp) -{ - StreamBlockJob *s =3D container_of(job, StreamBlockJob, common); - - if (speed < 0) { - error_setg(errp, QERR_INVALID_PARAMETER, "speed"); - return; - } - ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); -} - static const BlockJobDriver stream_job_driver =3D { .instance_size =3D sizeof(StreamBlockJob), .job_type =3D BLOCK_JOB_TYPE_STREAM, - .set_speed =3D stream_set_speed, .start =3D stream_run, }; =20 diff --git a/blockjob.c b/blockjob.c index 46c8923986..9b79abc821 100644 --- a/blockjob.c +++ b/blockjob.c @@ -659,22 +659,18 @@ static bool block_job_timer_pending(BlockJob *job) =20 void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) { - Error *local_err =3D NULL; int64_t old_speed =3D job->speed; =20 - if (!job->driver->set_speed) { - error_setg(errp, QERR_UNSUPPORTED); - return; - } if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) { return; } - job->driver->set_speed(job, speed, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (speed < 0) { + error_setg(errp, QERR_INVALID_PARAMETER, "speed"); return; } =20 + ratelimit_set_speed(&job->limit, speed, SLICE_TIME); + job->speed =3D speed; if (speed && speed <=3D old_speed) { return; --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524583849678611.0140184604726; Tue, 24 Apr 2018 08:30:49 -0700 (PDT) Received: from localhost ([::1]:59110 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzty-0003YP-Qs for importer@patchew.org; Tue, 24 Apr 2018 11:30:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47477) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzoz-0007k5-1G for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzox-0007im-Gu for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:32 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:50732 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzou-0007aV-6X; Tue, 24 Apr 2018 11:25:28 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BFEAFC934A; Tue, 24 Apr 2018 15:25:27 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id B0D42202342F; Tue, 24 Apr 2018 15:25:26 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:46 +0200 Message-Id: <20180424152515.25664-5-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 24 Apr 2018 15:25:27 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 24 Apr 2018 15:25:27 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 04/33] blockjob: Introduce block_job_ratelimit_get_delay() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This gets us rid of more direct accesses to BlockJob fields from the job drivers. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- include/block/blockjob_int.h | 8 ++++++++ block/backup.c | 18 +++++++----------- block/commit.c | 4 ++-- block/mirror.c | 5 +---- block/stream.c | 4 ++-- blockjob.c | 9 +++++++++ 6 files changed, 29 insertions(+), 19 deletions(-) diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 870bd346a8..d26115207b 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -166,6 +166,14 @@ void block_job_sleep_ns(BlockJob *job, int64_t ns); void block_job_yield(BlockJob *job); =20 /** + * block_job_ratelimit_get_delay: + * + * Calculate and return delay for the next request in ns. See the docuemnt= ation + * of ratelimit_calculate_delay() for details. + */ +int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n); + +/** * block_job_pause_all: * * Asynchronously pause all jobs. diff --git a/block/backup.c b/block/backup.c index 8468fd9f94..3f3ec6e408 100644 --- a/block/backup.c +++ b/block/backup.c @@ -325,21 +325,17 @@ static void backup_complete(BlockJob *job, void *opaq= ue) =20 static bool coroutine_fn yield_and_check(BackupBlockJob *job) { + uint64_t delay_ns; + if (block_job_is_cancelled(&job->common)) { return true; } =20 - /* we need to yield so that bdrv_drain_all() returns. - * (without, VM does not reboot) - */ - if (job->common.speed) { - uint64_t delay_ns =3D ratelimit_calculate_delay(&job->common.limit, - job->bytes_read); - job->bytes_read =3D 0; - block_job_sleep_ns(&job->common, delay_ns); - } else { - block_job_sleep_ns(&job->common, 0); - } + /* we need to yield even for delay_ns =3D 0 so that bdrv_drain_all() r= eturns. + * (without it, the VM does not reboot) */ + delay_ns =3D block_job_ratelimit_get_delay(&job->common, job->bytes_re= ad); + job->bytes_read =3D 0; + block_job_sleep_ns(&job->common, delay_ns); =20 if (block_job_is_cancelled(&job->common)) { return true; diff --git a/block/commit.c b/block/commit.c index 46cbeaec3e..ba5df6aa0a 100644 --- a/block/commit.c +++ b/block/commit.c @@ -197,8 +197,8 @@ static void coroutine_fn commit_run(void *opaque) /* Publish progress */ block_job_progress_update(&s->common, n); =20 - if (copy && s->common.speed) { - delay_ns =3D ratelimit_calculate_delay(&s->common.limit, n); + if (copy) { + delay_ns =3D block_job_ratelimit_get_delay(&s->common, n); } else { delay_ns =3D 0; } diff --git a/block/mirror.c b/block/mirror.c index de495fddc4..1cbdb1e0d8 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -447,10 +447,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBl= ockJob *s) assert(io_bytes); offset +=3D io_bytes; nb_chunks -=3D DIV_ROUND_UP(io_bytes, s->granularity); - if (s->common.speed) { - delay_ns =3D ratelimit_calculate_delay(&s->common.limit, - io_bytes_acct); - } + delay_ns =3D block_job_ratelimit_get_delay(&s->common, io_bytes_ac= ct); } return delay_ns; } diff --git a/block/stream.c b/block/stream.c index 797d7c4f21..df9660d2fc 100644 --- a/block/stream.c +++ b/block/stream.c @@ -185,8 +185,8 @@ static void coroutine_fn stream_run(void *opaque) =20 /* Publish progress */ block_job_progress_update(&s->common, n); - if (copy && s->common.speed) { - delay_ns =3D ratelimit_calculate_delay(&s->common.limit, n); + if (copy) { + delay_ns =3D block_job_ratelimit_get_delay(&s->common, n); } else { delay_ns =3D 0; } diff --git a/blockjob.c b/blockjob.c index 9b79abc821..31130d87cc 100644 --- a/blockjob.c +++ b/blockjob.c @@ -680,6 +680,15 @@ void block_job_set_speed(BlockJob *job, int64_t speed,= Error **errp) block_job_enter_cond(job, block_job_timer_pending); } =20 +int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) +{ + if (!job->speed) { + return 0; + } + + return ratelimit_calculate_delay(&job->limit, n); +} + void block_job_complete(BlockJob *job, Error **errp) { /* Should not be reachable via external interface for internal jobs */ --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585497892598.6075181536335; Tue, 24 Apr 2018 08:58:17 -0700 (PDT) Received: from localhost ([::1]:59283 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Kf-0000Hw-3l for importer@patchew.org; Tue, 24 Apr 2018 11:58:17 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47545) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzp3-0007pD-BF for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzp1-0007sS-Ux for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:37 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45618 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzov-0007ck-Em; Tue, 24 Apr 2018 11:25:29 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 184384067EF0; Tue, 24 Apr 2018 15:25:29 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 07AAC2026990; Tue, 24 Apr 2018 15:25:27 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:47 +0200 Message-Id: <20180424152515.25664-6-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:25:29 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:25:29 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 05/33] blockjob: Add block_job_driver() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The backup block job directly accesses the driver field in BlockJob. Add a wrapper for getting it. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- include/block/blockjob.h | 7 +++++++ block/backup.c | 8 +++++--- blockjob.c | 5 +++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 5aa8a6aaec..0b57d53084 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -452,4 +452,11 @@ void block_job_txn_add_job(BlockJobTxn *txn, BlockJob = *job); */ bool block_job_is_internal(BlockJob *job); =20 +/** + * block_job_driver: + * + * Returns the driver associated with a block job. + */ +const BlockJobDriver *block_job_driver(BlockJob *job); + #endif diff --git a/block/backup.c b/block/backup.c index 3f3ec6e408..1bc164d8ee 100644 --- a/block/backup.c +++ b/block/backup.c @@ -47,6 +47,8 @@ typedef struct BackupBlockJob { HBitmap *copy_bitmap; } BackupBlockJob; =20 +static const BlockJobDriver backup_job_driver; + /* See if in-flight requests overlap and wait for them to complete */ static void coroutine_fn wait_for_overlapping_requests(BackupBlockJob *job, int64_t start, @@ -241,7 +243,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp) BackupBlockJob *backup_job =3D container_of(job, BackupBlockJob, commo= n); int64_t len; =20 - assert(job->driver->job_type =3D=3D BLOCK_JOB_TYPE_BACKUP); + assert(block_job_driver(job) =3D=3D &backup_job_driver); =20 if (backup_job->sync_mode !=3D MIRROR_SYNC_MODE_NONE) { error_setg(errp, "The backup job only supports block checkpoint in" @@ -259,7 +261,7 @@ void backup_wait_for_overlapping_requests(BlockJob *job= , int64_t offset, BackupBlockJob *backup_job =3D container_of(job, BackupBlockJob, commo= n); int64_t start, end; =20 - assert(job->driver->job_type =3D=3D BLOCK_JOB_TYPE_BACKUP); + assert(block_job_driver(job) =3D=3D &backup_job_driver); =20 start =3D QEMU_ALIGN_DOWN(offset, backup_job->cluster_size); end =3D QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size); @@ -272,7 +274,7 @@ void backup_cow_request_begin(CowRequest *req, BlockJob= *job, BackupBlockJob *backup_job =3D container_of(job, BackupBlockJob, commo= n); int64_t start, end; =20 - assert(job->driver->job_type =3D=3D BLOCK_JOB_TYPE_BACKUP); + assert(block_job_driver(job) =3D=3D &backup_job_driver); =20 start =3D QEMU_ALIGN_DOWN(offset, backup_job->cluster_size); end =3D QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size); diff --git a/blockjob.c b/blockjob.c index 31130d87cc..42e34aa704 100644 --- a/blockjob.c +++ b/blockjob.c @@ -359,6 +359,11 @@ static bool block_job_started(BlockJob *job) return job->co; } =20 +const BlockJobDriver *block_job_driver(BlockJob *job) +{ + return job->driver; +} + /** * All jobs must allow a pause point before entering their job proper. This * ensures that jobs can be paused prior to being started, then resumed la= ter. --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584701571958.9449113095233; Tue, 24 Apr 2018 08:45:01 -0700 (PDT) Received: from localhost ([::1]:59196 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB07l-0006B8-2p for importer@patchew.org; Tue, 24 Apr 2018 11:44:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47557) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzp3-0007pl-QS for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzp2-0007tx-RJ for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:37 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34832 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzow-0007ff-P5; Tue, 24 Apr 2018 11:25:30 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 61CC2FA46C; Tue, 24 Apr 2018 15:25:30 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 52E55202342F; Tue, 24 Apr 2018 15:25:29 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:48 +0200 Message-Id: <20180424152515.25664-7-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:30 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:30 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 06/33] blockjob: Remove block_job_pause/resume_all() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Commit 81193349 removed the only use of block_job_pause/resume_all(), which was in bdrv_drain_all(). The functions are now unused and can be removed. Signed-off-by: Kevin Wolf --- include/block/blockjob_int.h | 14 -------------- blockjob.c | 27 --------------------------- 2 files changed, 41 deletions(-) diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index d26115207b..6a3d03ef0f 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -174,20 +174,6 @@ void block_job_yield(BlockJob *job); int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n); =20 /** - * block_job_pause_all: - * - * Asynchronously pause all jobs. - */ -void block_job_pause_all(void); - -/** - * block_job_resume_all: - * - * Resume all block jobs. Must be paired with a preceding block_job_pause= _all. - */ -void block_job_resume_all(void); - -/** * block_job_early_fail: * @bs: The block device. * diff --git a/blockjob.c b/blockjob.c index 42e34aa704..de64bdba7a 100644 --- a/blockjob.c +++ b/blockjob.c @@ -1008,19 +1008,6 @@ void *block_job_create(const char *job_id, const Blo= ckJobDriver *driver, return job; } =20 -void block_job_pause_all(void) -{ - BlockJob *job =3D NULL; - while ((job =3D block_job_next(job))) { - AioContext *aio_context =3D blk_get_aio_context(job->blk); - - aio_context_acquire(aio_context); - block_job_ref(job); - block_job_pause(job); - aio_context_release(aio_context); - } -} - void block_job_early_fail(BlockJob *job) { assert(job->status =3D=3D BLOCK_JOB_STATUS_CREATED); @@ -1098,20 +1085,6 @@ void coroutine_fn block_job_pause_point(BlockJob *jo= b) } } =20 -void block_job_resume_all(void) -{ - BlockJob *job, *next; - - QLIST_FOREACH_SAFE(job, &block_jobs, job_list, next) { - AioContext *aio_context =3D blk_get_aio_context(job->blk); - - aio_context_acquire(aio_context); - block_job_resume(job); - block_job_unref(job); - aio_context_release(aio_context); - } -} - /* * Conditionally enter a block_job pending a call to fn() while * under the block_job_lock critical section. --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585886390817.8541496324714; Tue, 24 Apr 2018 09:04:46 -0700 (PDT) Received: from localhost ([::1]:59326 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Qv-0005bv-Bx for importer@patchew.org; Tue, 24 Apr 2018 12:04:45 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47744) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpB-0007y8-0x for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzp7-000832-De for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:44 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59822 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzoy-0007jh-74; Tue, 24 Apr 2018 11:25:32 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CC61A406C7AC; Tue, 24 Apr 2018 15:25:31 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9DDC2202323A; Tue, 24 Apr 2018 15:25:30 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:49 +0200 Message-Id: <20180424152515.25664-8-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:31 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:31 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 07/33] job: Create Job, JobDriver and job_create() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This is the first step towards creating an infrastructure for generic background jobs that aren't tied to a block device. For now, Job only stores its ID and JobDriver, the rest stays in BlockJob. The following patches will move over more parts of BlockJob to Job if they are meaningful outside the context of a block job. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 9 +++---- include/block/blockjob_int.h | 4 +-- include/qemu/job.h | 60 ++++++++++++++++++++++++++++++++++++++++= ++++ block/backup.c | 4 ++- block/commit.c | 4 ++- block/mirror.c | 10 +++++--- block/stream.c | 4 ++- blockjob.c | 46 ++++++++++++++++----------------- job.c | 48 +++++++++++++++++++++++++++++++++++ tests/test-bdrv-drain.c | 4 ++- tests/test-blockjob-txn.c | 4 ++- tests/test-blockjob.c | 12 ++++++--- MAINTAINERS | 2 ++ Makefile.objs | 2 +- 14 files changed, 169 insertions(+), 44 deletions(-) create mode 100644 include/qemu/job.h create mode 100644 job.c diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 0b57d53084..8acc1a236a 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -26,6 +26,7 @@ #ifndef BLOCKJOB_H #define BLOCKJOB_H =20 +#include "qemu/job.h" #include "block/block.h" #include "qemu/ratelimit.h" =20 @@ -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; =20 @@ -47,11 +51,6 @@ typedef struct BlockJob { BlockBackend *blk; =20 /** - * 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 6a3d03ef0f..a357ad6c5e 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; =20 /** 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"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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/block/backup.c b/block/backup.c index 1bc164d8ee..fa468a64bb 100644 --- a/block/backup.c +++ b/block/backup.c @@ -523,7 +523,9 @@ static void coroutine_fn backup_run(void *opaque) } =20 static const BlockJobDriver backup_job_driver =3D { - .instance_size =3D sizeof(BackupBlockJob), + .job_driver =3D { + .instance_size =3D sizeof(BackupBlockJob), + }, .job_type =3D BLOCK_JOB_TYPE_BACKUP, .start =3D backup_run, .commit =3D 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: } =20 static const BlockJobDriver commit_job_driver =3D { - .instance_size =3D sizeof(CommitBlockJob), + .job_driver =3D { + .instance_size =3D sizeof(CommitBlockJob), + }, .job_type =3D BLOCK_JOB_TYPE_COMMIT, .start =3D commit_run, }; diff --git a/block/mirror.c b/block/mirror.c index 1cbdb1e0d8..84de8105e6 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -909,7 +909,7 @@ static void mirror_complete(BlockJob *job, Error **errp) =20 if (!s->synced) { error_setg(errp, "The active block job '%s' cannot be completed", - job->id); + job->job.id); return; } =20 @@ -982,7 +982,9 @@ static void mirror_drain(BlockJob *job) } =20 static const BlockJobDriver mirror_job_driver =3D { - .instance_size =3D sizeof(MirrorBlockJob), + .job_driver =3D { + .instance_size =3D sizeof(MirrorBlockJob), + }, .job_type =3D BLOCK_JOB_TYPE_MIRROR, .start =3D mirror_run, .complete =3D mirror_complete, @@ -992,7 +994,9 @@ static const BlockJobDriver mirror_job_driver =3D { }; =20 static const BlockJobDriver commit_active_job_driver =3D { - .instance_size =3D sizeof(MirrorBlockJob), + .job_driver =3D { + .instance_size =3D sizeof(MirrorBlockJob), + }, .job_type =3D BLOCK_JOB_TYPE_COMMIT, .start =3D mirror_run, .complete =3D 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: } =20 static const BlockJobDriver stream_job_driver =3D { - .instance_size =3D sizeof(StreamBlockJob), + .job_driver =3D { + .instance_size =3D sizeof(StreamBlockJob), + }, .job_type =3D BLOCK_JOB_TYPE_STREAM, .start =3D stream_run, }; diff --git a/blockjob.c b/blockjob.c index de64bdba7a..abdfc68729 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" =20 /* Right now, this mutex is only needed to synchronize accesses to job->bu= sy @@ -92,7 +91,8 @@ static int block_job_apply_verb(BlockJob *job, BlockJobVe= rb 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; } =20 @@ -159,7 +159,7 @@ BlockJob *block_job_get(const char *id) BlockJob *job; =20 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; } } @@ -247,7 +247,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); } @@ -297,7 +297,7 @@ static char *child_job_get_parent_desc(BdrvChild *c) BlockJob *job =3D c->opaque; return g_strdup_printf("%s job '%s'", BlockJobType_str(job->driver->job_type), - job->id); + job->job.id); } =20 static void child_job_drained_begin(BdrvChild *c) @@ -351,7 +351,7 @@ int block_job_add_bdrv(BlockJob *job, const char *name,= BlockDriverState *bs, =20 bool block_job_is_internal(BlockJob *job) { - return (job->id =3D=3D NULL); + return (job->job.id =3D=3D NULL); } =20 static bool block_job_started(BlockJob *job) @@ -697,13 +697,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; } =20 @@ -712,7 +712,7 @@ void block_job_complete(BlockJob *job, Error **errp) =20 void block_job_finalize(BlockJob *job, Error **errp) { - assert(job && job->id && job->txn); + assert(job && job->job.id && job->txn); if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) { return; } @@ -723,7 +723,7 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) { BlockJob *job =3D *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; } @@ -840,7 +840,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **er= rp) } info =3D g_new0(BlockJobInfo, 1); info->type =3D g_strdup(BlockJobType_str(job->driver->job_type)); - info->device =3D g_strdup(job->id); + info->device =3D g_strdup(job->job.id); info->len =3D job->len; info->busy =3D atomic_read(&job->busy); info->paused =3D job->pause_count > 0; @@ -869,7 +869,7 @@ static void block_job_event_cancelled(BlockJob *job) } =20 qapi_event_send_block_job_cancelled(job->driver->job_type, - job->id, + job->job.id, job->len, job->offset, job->speed, @@ -883,7 +883,7 @@ static void block_job_event_completed(BlockJob *job, co= nst char *msg) } =20 qapi_event_send_block_job_completed(job->driver->job_type, - job->id, + job->job.id, job->len, job->offset, job->speed, @@ -897,7 +897,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; @@ -935,12 +935,6 @@ void *block_job_create(const char *job_id, const Block= JobDriver *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; @@ -954,9 +948,13 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, return NULL; } =20 - job =3D g_malloc0(driver->instance_size); + job =3D job_create(job_id, &driver->job_driver, errp); + if (job =3D=3D NULL) { + blk_unref(blk); + return NULL; + } + job->driver =3D driver; - job->id =3D g_strdup(job_id); job->blk =3D blk; job->cb =3D cb; job->opaque =3D opaque; @@ -1177,7 +1175,7 @@ void block_job_event_ready(BlockJob *job) } =20 qapi_event_send_block_job_ready(job->driver->job_type, - job->id, + job->job.id, job->len, job->offset, job->speed, &error_abort); @@ -1207,7 +1205,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/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"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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 =3D g_malloc0(driver->instance_size); + job->driver =3D driver; + job->id =3D 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 **er= rp) } =20 BlockJobDriver test_job_driver =3D { - .instance_size =3D sizeof(TestBlockJob), + .job_driver =3D { + .instance_size =3D sizeof(TestBlockJob), + }, .start =3D test_job_start, .complete =3D 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) } =20 static const BlockJobDriver test_block_job_driver =3D { - .instance_size =3D sizeof(TestBlockJob), + .job_driver =3D { + .instance_size =3D sizeof(TestBlockJob), + }, .start =3D test_block_job_run, }; =20 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" =20 static const BlockJobDriver test_block_job_driver =3D { - .instance_size =3D sizeof(BlockJob), + .job_driver =3D { + .instance_size =3D sizeof(BlockJob), + }, }; =20 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, =3D=3D, id); + g_assert_cmpstr(job->job.id, =3D=3D, id); } else { - g_assert_cmpstr(job->id, =3D=3D, blk_name(blk)); + g_assert_cmpstr(job->job.id, =3D=3D, blk_name(blk)); } } else { g_assert_nonnull(errp); @@ -192,7 +194,9 @@ static void coroutine_fn cancel_job_start(void *opaque) } =20 static const BlockJobDriver test_cancel_driver =3D { - .instance_size =3D sizeof(CancelJob), + .job_driver =3D { + .instance_size =3D sizeof(CancelJob), + }, .start =3D cancel_job_start, .complete =3D cancel_job_complete, }; diff --git a/MAINTAINERS b/MAINTAINERS index 24b70169bc..f78b8b865b 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 =3D chardev/ # block-obj-y is code used by both qemu system emulation and qemu-img =20 block-obj-y +=3D nbd/ -block-obj-y +=3D block.o blockjob.o +block-obj-y +=3D block.o blockjob.o job.o block-obj-y +=3D block/ scsi/ block-obj-y +=3D qemu-io-cmds.o block-obj-$(CONFIG_REPLICATION) +=3D replication.o --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584325399970.2602514703979; Tue, 24 Apr 2018 08:38:45 -0700 (PDT) Received: from localhost ([::1]:59155 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB01i-00015J-4U for importer@patchew.org; Tue, 24 Apr 2018 11:38:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47594) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzp4-0007qy-R2 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzp3-0007vO-CB for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:38 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34834 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzoz-0007mr-G6; Tue, 24 Apr 2018 11:25:33 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2590A738E0; Tue, 24 Apr 2018 15:25:33 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 13EC1202342F; Tue, 24 Apr 2018 15:25:31 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:50 +0200 Message-Id: <20180424152515.25664-9-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:33 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:33 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 08/33] job: Rename BlockJobType into JobType X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" QAPI types aren't externally visible, so we can rename them without causing problems. Before we add a job type to Job, rename the enum so it can be used for more than just block jobs. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- qapi/block-core.json | 14 +++++++------- include/block/blockjob_int.h | 2 +- block/backup.c | 2 +- block/commit.c | 2 +- block/mirror.c | 4 ++-- block/stream.c | 2 +- blockjob.c | 6 +++--- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index c50517bff3..f2579d46f8 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1050,9 +1050,9 @@ 'data': ['top', 'full', 'none', 'incremental'] } =20 ## -# @BlockJobType: +# @JobType: # -# Type of a block job. +# Type of a background job. # # @commit: block commit job type, see "block-commit" # @@ -1064,7 +1064,7 @@ # # Since: 1.7 ## -{ 'enum': 'BlockJobType', +{ 'enum': 'JobType', 'data': ['commit', 'stream', 'mirror', 'backup'] } =20 ## @@ -4485,7 +4485,7 @@ # ## { 'event': 'BLOCK_JOB_COMPLETED', - 'data': { 'type' : 'BlockJobType', + 'data': { 'type' : 'JobType', 'device': 'str', 'len' : 'int', 'offset': 'int', @@ -4521,7 +4521,7 @@ # ## { 'event': 'BLOCK_JOB_CANCELLED', - 'data': { 'type' : 'BlockJobType', + 'data': { 'type' : 'JobType', 'device': 'str', 'len' : 'int', 'offset': 'int', @@ -4586,7 +4586,7 @@ # ## { 'event': 'BLOCK_JOB_READY', - 'data': { 'type' : 'BlockJobType', + 'data': { 'type' : 'JobType', 'device': 'str', 'len' : 'int', 'offset': 'int', @@ -4613,7 +4613,7 @@ # ## { 'event': 'BLOCK_JOB_PENDING', - 'data': { 'type' : 'BlockJobType', + 'data': { 'type' : 'JobType', 'id' : 'str' } } =20 ## diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index a357ad6c5e..3dddd54d43 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -39,7 +39,7 @@ struct BlockJobDriver { JobDriver job_driver; =20 /** String describing the operation, part of query-block-jobs QMP API = */ - BlockJobType job_type; + JobType job_type; =20 /** Mandatory: Entrypoint for the Coroutine. */ CoroutineEntry *start; diff --git a/block/backup.c b/block/backup.c index fa468a64bb..1a23e6fb63 100644 --- a/block/backup.c +++ b/block/backup.c @@ -526,7 +526,7 @@ static const BlockJobDriver backup_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(BackupBlockJob), }, - .job_type =3D BLOCK_JOB_TYPE_BACKUP, + .job_type =3D JOB_TYPE_BACKUP, .start =3D backup_run, .commit =3D backup_commit, .abort =3D backup_abort, diff --git a/block/commit.c b/block/commit.c index 18cbb2f9c4..afa2b2bacf 100644 --- a/block/commit.c +++ b/block/commit.c @@ -218,7 +218,7 @@ static const BlockJobDriver commit_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(CommitBlockJob), }, - .job_type =3D BLOCK_JOB_TYPE_COMMIT, + .job_type =3D JOB_TYPE_COMMIT, .start =3D commit_run, }; =20 diff --git a/block/mirror.c b/block/mirror.c index 84de8105e6..8cf275d87f 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -985,7 +985,7 @@ static const BlockJobDriver mirror_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), }, - .job_type =3D BLOCK_JOB_TYPE_MIRROR, + .job_type =3D JOB_TYPE_MIRROR, .start =3D mirror_run, .complete =3D mirror_complete, .pause =3D mirror_pause, @@ -997,7 +997,7 @@ static const BlockJobDriver commit_active_job_driver = =3D { .job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), }, - .job_type =3D BLOCK_JOB_TYPE_COMMIT, + .job_type =3D JOB_TYPE_COMMIT, .start =3D mirror_run, .complete =3D mirror_complete, .pause =3D mirror_pause, diff --git a/block/stream.c b/block/stream.c index f88fc75141..048bceb5d0 100644 --- a/block/stream.c +++ b/block/stream.c @@ -212,7 +212,7 @@ static const BlockJobDriver stream_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(StreamBlockJob), }, - .job_type =3D BLOCK_JOB_TYPE_STREAM, + .job_type =3D JOB_TYPE_STREAM, .start =3D stream_run, }; =20 diff --git a/blockjob.c b/blockjob.c index abdfc68729..dad6e509f0 100644 --- a/blockjob.c +++ b/blockjob.c @@ -296,7 +296,7 @@ static char *child_job_get_parent_desc(BdrvChild *c) { BlockJob *job =3D c->opaque; return g_strdup_printf("%s job '%s'", - BlockJobType_str(job->driver->job_type), + JobType_str(job->driver->job_type), job->job.id); } =20 @@ -839,7 +839,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **er= rp) return NULL; } info =3D g_new0(BlockJobInfo, 1); - info->type =3D g_strdup(BlockJobType_str(job->driver->job_type)); + info->type =3D g_strdup(JobType_str(job->driver->job_type)); info->device =3D g_strdup(job->job.id); info->len =3D job->len; info->busy =3D atomic_read(&job->busy); @@ -970,7 +970,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, block_job_sleep_timer_cb, job); =20 error_setg(&job->blocker, "block device is in use by block job: %s", - BlockJobType_str(driver->job_type)); + JobType_str(driver->job_type)); block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort= ); bs->job =3D job; =20 --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585692098677.949753823574; Tue, 24 Apr 2018 09:01:32 -0700 (PDT) Received: from localhost ([::1]:59311 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Nn-00031I-8F for importer@patchew.org; Tue, 24 Apr 2018 12:01:31 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47663) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzp7-0007uE-F6 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzp5-0007zV-2D for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:41 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59824 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzp0-0007py-R5; Tue, 24 Apr 2018 11:25:35 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6FC31406C7AC; Tue, 24 Apr 2018 15:25:34 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 60E512026990; Tue, 24 Apr 2018 15:25:33 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:51 +0200 Message-Id: <20180424152515.25664-10-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:34 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:34 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 09/33] job: Add JobDriver.job_type X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves the job_type field from BlockJobDriver to JobDriver. Signed-off-by: Kevin Wolf --- include/block/blockjob_int.h | 3 --- include/qemu/job.h | 11 +++++++++++ block/backup.c | 2 +- block/commit.c | 2 +- block/mirror.c | 4 ++-- block/stream.c | 2 +- blockjob.c | 16 +++++++--------- job.c | 10 ++++++++++ 8 files changed, 33 insertions(+), 17 deletions(-) diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 3dddd54d43..699a6d1487 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -38,9 +38,6 @@ struct BlockJobDriver { /** Generic JobDriver callbacks and settings */ JobDriver job_driver; =20 - /** String describing the operation, part of query-block-jobs QMP API = */ - JobType job_type; - /** Mandatory: Entrypoint for the Coroutine. */ CoroutineEntry *start; =20 diff --git a/include/qemu/job.h b/include/qemu/job.h index b4b49f19e1..c87e951c8a 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -26,6 +26,8 @@ #ifndef JOB_H #define JOB_H =20 +#include "qapi/qapi-types-block-core.h" + typedef struct JobDriver JobDriver; =20 /** @@ -45,6 +47,9 @@ typedef struct Job { struct JobDriver { /** Derived Job struct size */ size_t instance_size; + + /** Enum describing the operation */ + JobType job_type; }; =20 =20 @@ -57,4 +62,10 @@ struct JobDriver { */ void *job_create(const char *job_id, const JobDriver *driver, Error **errp= ); =20 +/** Returns the JobType of a given Job. */ +JobType job_type(Job *job); + +/** Returns the enum string for the JobType of a given Job. */ +const char *job_type_str(Job *job); + #endif diff --git a/block/backup.c b/block/backup.c index 1a23e6fb63..780c2bde90 100644 --- a/block/backup.c +++ b/block/backup.c @@ -525,8 +525,8 @@ static void coroutine_fn backup_run(void *opaque) static const BlockJobDriver backup_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(BackupBlockJob), + .job_type =3D JOB_TYPE_BACKUP, }, - .job_type =3D JOB_TYPE_BACKUP, .start =3D backup_run, .commit =3D backup_commit, .abort =3D backup_abort, diff --git a/block/commit.c b/block/commit.c index afa2b2bacf..32d29c890e 100644 --- a/block/commit.c +++ b/block/commit.c @@ -217,8 +217,8 @@ out: static const BlockJobDriver commit_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(CommitBlockJob), + .job_type =3D JOB_TYPE_COMMIT, }, - .job_type =3D JOB_TYPE_COMMIT, .start =3D commit_run, }; =20 diff --git a/block/mirror.c b/block/mirror.c index 8cf275d87f..2c014a2b96 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -984,8 +984,8 @@ static void mirror_drain(BlockJob *job) static const BlockJobDriver mirror_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), + .job_type =3D JOB_TYPE_MIRROR, }, - .job_type =3D JOB_TYPE_MIRROR, .start =3D mirror_run, .complete =3D mirror_complete, .pause =3D mirror_pause, @@ -996,8 +996,8 @@ static const BlockJobDriver mirror_job_driver =3D { static const BlockJobDriver commit_active_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), + .job_type =3D JOB_TYPE_COMMIT, }, - .job_type =3D JOB_TYPE_COMMIT, .start =3D mirror_run, .complete =3D mirror_complete, .pause =3D mirror_pause, diff --git a/block/stream.c b/block/stream.c index 048bceb5d0..cb723f190a 100644 --- a/block/stream.c +++ b/block/stream.c @@ -211,8 +211,8 @@ out: static const BlockJobDriver stream_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(StreamBlockJob), + .job_type =3D JOB_TYPE_STREAM, }, - .job_type =3D JOB_TYPE_STREAM, .start =3D stream_run, }; =20 diff --git a/blockjob.c b/blockjob.c index dad6e509f0..5e766057e1 100644 --- a/blockjob.c +++ b/blockjob.c @@ -295,9 +295,7 @@ static void block_job_detach_aio_context(void *opaque) static char *child_job_get_parent_desc(BdrvChild *c) { BlockJob *job =3D c->opaque; - return g_strdup_printf("%s job '%s'", - JobType_str(job->driver->job_type), - job->job.id); + return g_strdup_printf("%s job '%s'", job_type_str(&job->job), job->jo= b.id); } =20 static void child_job_drained_begin(BdrvChild *c) @@ -839,7 +837,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **er= rp) return NULL; } info =3D g_new0(BlockJobInfo, 1); - info->type =3D g_strdup(JobType_str(job->driver->job_type)); + info->type =3D g_strdup(job_type_str(&job->job)); info->device =3D g_strdup(job->job.id); info->len =3D job->len; info->busy =3D atomic_read(&job->busy); @@ -868,7 +866,7 @@ static void block_job_event_cancelled(BlockJob *job) return; } =20 - qapi_event_send_block_job_cancelled(job->driver->job_type, + qapi_event_send_block_job_cancelled(job_type(&job->job), job->job.id, job->len, job->offset, @@ -882,7 +880,7 @@ static void block_job_event_completed(BlockJob *job, co= nst char *msg) return; } =20 - qapi_event_send_block_job_completed(job->driver->job_type, + qapi_event_send_block_job_completed(job_type(&job->job), job->job.id, job->len, job->offset, @@ -896,7 +894,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, + qapi_event_send_block_job_pending(job_type(&job->job), job->job.id, &error_abort); } @@ -970,7 +968,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, block_job_sleep_timer_cb, job); =20 error_setg(&job->blocker, "block device is in use by block job: %s", - JobType_str(driver->job_type)); + job_type_str(&job->job)); block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort= ); bs->job =3D job; =20 @@ -1174,7 +1172,7 @@ void block_job_event_ready(BlockJob *job) return; } =20 - qapi_event_send_block_job_ready(job->driver->job_type, + qapi_event_send_block_job_ready(job_type(&job->job), job->job.id, job->len, job->offset, diff --git a/job.c b/job.c index 87fd48468c..f00f401502 100644 --- a/job.c +++ b/job.c @@ -29,6 +29,16 @@ #include "qemu/job.h" #include "qemu/id.h" =20 +JobType job_type(Job *job) +{ + return job->driver->job_type; +} + +const char *job_type_str(Job *job) +{ + return JobType_str(job_type(job)); +} + void *job_create(const char *job_id, const JobDriver *driver, Error **errp) { Job *job; --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152458488829136.549902536593436; Tue, 24 Apr 2018 08:48:08 -0700 (PDT) Received: from localhost ([::1]:59216 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Ap-0000Fq-EG for importer@patchew.org; Tue, 24 Apr 2018 11:48:07 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47626) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzp6-0007sm-66 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzp4-0007yu-RY for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:40 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57164 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzp2-0007sI-4O; Tue, 24 Apr 2018 11:25:36 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B9B2581A88A2; Tue, 24 Apr 2018 15:25:35 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id AAEB5202342F; Tue, 24 Apr 2018 15:25:34 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:52 +0200 Message-Id: <20180424152515.25664-11-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 24 Apr 2018 15:25:35 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 24 Apr 2018 15:25:35 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 10/33] job: Add job_delete() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves freeing the Job object and its fields from block_job_unref() to job_delete(). Signed-off-by: Kevin Wolf --- include/qemu/job.h | 3 +++ blockjob.c | 3 +-- job.c | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/qemu/job.h b/include/qemu/job.h index c87e951c8a..ee1f5d1ef4 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -62,6 +62,9 @@ struct JobDriver { */ void *job_create(const char *job_id, const JobDriver *driver, Error **errp= ); =20 +/** Frees the @job object. */ +void job_delete(Job *job); + /** Returns the JobType of a given Job. */ JobType job_type(Job *job); =20 diff --git a/blockjob.c b/blockjob.c index 5e766057e1..041a1e58d2 100644 --- a/blockjob.c +++ b/blockjob.c @@ -247,9 +247,8 @@ void block_job_unref(BlockJob *job) block_job_detach_aio_context, job); blk_unref(job->blk); error_free(job->blocker); - g_free(job->job.id); assert(!timer_pending(&job->sleep_timer)); - g_free(job); + job_delete(&job->job); } } =20 diff --git a/job.c b/job.c index f00f401502..a36425498d 100644 --- a/job.c +++ b/job.c @@ -56,3 +56,9 @@ void *job_create(const char *job_id, const JobDriver *dri= ver, Error **errp) =20 return job; } + +void job_delete(Job *job) +{ + g_free(job->id); + g_free(job); +} --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584515935260.00150650832506; Tue, 24 Apr 2018 08:41:55 -0700 (PDT) Received: from localhost ([::1]:59176 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB04i-0003bE-MY for importer@patchew.org; Tue, 24 Apr 2018 11:41:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47728) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpA-0007x7-CZ for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzp6-00082i-Ve for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:44 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45620 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzp3-0007uy-F2; Tue, 24 Apr 2018 11:25:37 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 10087407574E; Tue, 24 Apr 2018 15:25:37 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 00EB9202323A; Tue, 24 Apr 2018 15:25:35 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:53 +0200 Message-Id: <20180424152515.25664-12-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:25:37 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:25:37 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 11/33] job: Maintain a list of all jobs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves the job list from BlockJob to Job. Now we can check for duplicate IDs in job_create(). Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 3 --- include/qemu/job.h | 19 +++++++++++++++++++ blockjob.c | 47 +++++++++++++++++++++++++-------------------= --- job.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 25 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 8acc1a236a..8946f118f3 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -105,9 +105,6 @@ typedef struct BlockJob { */ bool deferred_to_main_loop; =20 - /** Element of the list of block jobs */ - QLIST_ENTRY(BlockJob) job_list; - /** Status that is published by the query-block-jobs QMP API */ BlockDeviceIoStatus iostatus; =20 diff --git a/include/qemu/job.h b/include/qemu/job.h index ee1f5d1ef4..6555ab4c36 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -27,6 +27,7 @@ #define JOB_H =20 #include "qapi/qapi-types-block-core.h" +#include "qemu/queue.h" =20 typedef struct JobDriver JobDriver; =20 @@ -39,6 +40,9 @@ typedef struct Job { =20 /** The type of this job. */ const JobDriver *driver; + + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; } Job; =20 /** @@ -71,4 +75,19 @@ JobType job_type(Job *job); /** Returns the enum string for the JobType of a given Job. */ const char *job_type_str(Job *job); =20 +/** + * Get the next element from the list of block jobs after @job, or the + * first one if @job is %NULL. + * + * Returns the requested job, or %NULL if there are no more jobs left. + */ +Job *job_next(Job *job); + +/** + * Get the job identified by @id (which must not be %NULL). + * + * Returns the requested job, or %NULL if it doesn't exist. + */ +Job *job_get(const char *id); + #endif diff --git a/blockjob.c b/blockjob.c index 041a1e58d2..6020a067a3 100644 --- a/blockjob.c +++ b/blockjob.c @@ -129,8 +129,6 @@ struct BlockJobTxn { int refcnt; }; =20 -static QLIST_HEAD(, BlockJob) block_jobs =3D QLIST_HEAD_INITIALIZER(block_= jobs); - /* * The block job API is composed of two categories of functions. * @@ -146,25 +144,35 @@ static QLIST_HEAD(, BlockJob) block_jobs =3D QLIST_HE= AD_INITIALIZER(block_jobs); * blockjob_int.h. */ =20 -BlockJob *block_job_next(BlockJob *job) +static bool is_block_job(Job *job) { - if (!job) { - return QLIST_FIRST(&block_jobs); - } - return QLIST_NEXT(job, job_list); + return job_type(job) =3D=3D JOB_TYPE_BACKUP || + job_type(job) =3D=3D JOB_TYPE_COMMIT || + job_type(job) =3D=3D JOB_TYPE_MIRROR || + job_type(job) =3D=3D JOB_TYPE_STREAM; +} + +BlockJob *block_job_next(BlockJob *bjob) +{ + Job *job =3D &bjob->job; + + do { + job =3D job_next(job); + } while (job && !is_block_job(job)); + + + return job ? container_of(job, BlockJob, job) : NULL; } =20 BlockJob *block_job_get(const char *id) { - BlockJob *job; + Job *job =3D job_get(id); =20 - QLIST_FOREACH(job, &block_jobs, job_list) { - if (job->job.id && !strcmp(id, job->job.id)) { - return job; - } + if (job && is_block_job(job)) { + return container_of(job, BlockJob, job); + } else { + return NULL; } - - return NULL; } =20 BlockJobTxn *block_job_txn_new(void) @@ -239,7 +247,6 @@ void block_job_unref(BlockJob *job) assert(job->status =3D=3D BLOCK_JOB_STATUS_NULL); assert(!job->txn); BlockDriverState *bs =3D blk_bs(job->blk); - QLIST_REMOVE(job, job_list); bs->job =3D NULL; block_job_remove_all_bdrv(job); blk_remove_aio_context_notifier(job->blk, @@ -804,7 +811,7 @@ void block_job_cancel_sync_all(void) BlockJob *job; AioContext *aio_context; =20 - while ((job =3D QLIST_FIRST(&block_jobs))) { + while ((job =3D block_job_next(NULL))) { aio_context =3D blk_get_aio_context(job->blk); aio_context_acquire(aio_context); block_job_cancel_sync(job); @@ -932,10 +939,6 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, error_setg(errp, "Cannot specify job ID for internal block job= "); return NULL; } - if (block_job_get(job_id)) { - error_setg(errp, "Job ID '%s' already in use", job_id); - return NULL; - } } =20 blk =3D blk_new(perm, shared_perm); @@ -951,6 +954,8 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, return NULL; } =20 + assert(is_block_job(&job->job)); + job->driver =3D driver; job->blk =3D blk; job->cb =3D cb; @@ -973,8 +978,6 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, =20 bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); =20 - QLIST_INSERT_HEAD(&block_jobs, job, job_list); - blk_add_aio_context_notifier(blk, block_job_attached_aio_context, block_job_detach_aio_context, job); =20 diff --git a/job.c b/job.c index a36425498d..00f7968c50 100644 --- a/job.c +++ b/job.c @@ -29,6 +29,8 @@ #include "qemu/job.h" #include "qemu/id.h" =20 +static QLIST_HEAD(, Job) jobs =3D QLIST_HEAD_INITIALIZER(jobs); + JobType job_type(Job *job) { return job->driver->job_type; @@ -39,6 +41,27 @@ const char *job_type_str(Job *job) return JobType_str(job_type(job)); } =20 +Job *job_next(Job *job) +{ + if (!job) { + return QLIST_FIRST(&jobs); + } + return QLIST_NEXT(job, job_list); +} + +Job *job_get(const char *id) +{ + Job *job; + + QLIST_FOREACH(job, &jobs, job_list) { + if (job->id && !strcmp(id, job->id)) { + return job; + } + } + + return NULL; +} + void *job_create(const char *job_id, const JobDriver *driver, Error **errp) { Job *job; @@ -48,17 +71,25 @@ void *job_create(const char *job_id, const JobDriver *d= river, Error **errp) error_setg(errp, "Invalid job ID '%s'", job_id); return NULL; } + if (job_get(job_id)) { + error_setg(errp, "Job ID '%s' already in use", job_id); + return NULL; + } } =20 job =3D g_malloc0(driver->instance_size); job->driver =3D driver; job->id =3D g_strdup(job_id); =20 + QLIST_INSERT_HEAD(&jobs, job, job_list); + return job; } =20 void job_delete(Job *job) { + QLIST_REMOVE(job, job_list); + g_free(job->id); g_free(job); } --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15245848897081010.7289415861969; Tue, 24 Apr 2018 08:48:09 -0700 (PDT) Received: from localhost ([::1]:59217 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Aq-0000Gj-Nz for importer@patchew.org; Tue, 24 Apr 2018 11:48:08 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47845) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpF-00084D-Hd for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpC-00088x-41 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:49 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:58894 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzp4-0007yF-Nz; Tue, 24 Apr 2018 11:25:38 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5BEA7401DE65; Tue, 24 Apr 2018 15:25:38 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4C114202342F; Tue, 24 Apr 2018 15:25:37 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:54 +0200 Message-Id: <20180424152515.25664-13-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 24 Apr 2018 15:25:38 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 24 Apr 2018 15:25:38 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 12/33] job: Move state transitions to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves BlockJob.status and the closely related functions (block_)job_state_transition() and (block_)job_apply_verb to Job. The two QAPI enums are renamed to JobStatus and JobVerb. Signed-off-by: Kevin Wolf --- qapi/block-core.json | 14 +++---- include/block/blockjob.h | 3 -- include/qemu/job.h | 7 ++++ blockjob.c | 102 +++++++++++--------------------------------= ---- job.c | 57 ++++++++++++++++++++++++++ tests/test-blockjob.c | 39 +++++++++--------- block/trace-events | 2 - trace-events | 4 ++ 8 files changed, 117 insertions(+), 111 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index f2579d46f8..d263fdfa3d 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1068,9 +1068,9 @@ 'data': ['commit', 'stream', 'mirror', 'backup'] } =20 ## -# @BlockJobVerb: +# @JobVerb: # -# Represents command verbs that can be applied to a blockjob. +# Represents command verbs that can be applied to a job. # # @cancel: see @block-job-cancel # @@ -1088,14 +1088,14 @@ # # Since: 2.12 ## -{ 'enum': 'BlockJobVerb', +{ 'enum': 'JobVerb', 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss', 'finalize' ] } =20 ## -# @BlockJobStatus: +# @JobStatus: # -# Indicates the present state of a given blockjob in its lifetime. +# Indicates the present state of a given job in its lifetime. # # @undefined: Erroneous, default state. Should not ever be visible. # @@ -1134,7 +1134,7 @@ # # Since: 2.12 ## -{ 'enum': 'BlockJobStatus', +{ 'enum': 'JobStatus', 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby', 'waiting', 'pending', 'aborting', 'concluded', 'null' ] } =20 @@ -1178,7 +1178,7 @@ 'data': {'type': 'str', 'device': 'str', 'len': 'int', 'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'in= t', 'io-status': 'BlockDeviceIoStatus', 'ready': 'bool', - 'status': 'BlockJobStatus', + 'status': 'JobStatus', 'auto-finalize': 'bool', 'auto-dismiss': 'bool' } } =20 ## diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 8946f118f3..96e5f67ed7 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -147,9 +147,6 @@ typedef struct BlockJob { */ QEMUTimer sleep_timer; =20 - /** Current state; See @BlockJobStatus for details. */ - BlockJobStatus status; - /** True if this job should automatically finalize itself */ bool auto_finalize; =20 diff --git a/include/qemu/job.h b/include/qemu/job.h index 6555ab4c36..c22054a7be 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -41,6 +41,9 @@ typedef struct Job { /** The type of this job. */ const JobDriver *driver; =20 + /** Current state; See @JobStatus for details. */ + JobStatus status; + /** Element of the list of jobs */ QLIST_ENTRY(Job) job_list; } Job; @@ -90,4 +93,8 @@ Job *job_next(Job *job); */ Job *job_get(const char *id); =20 +/* TODO To be removed from the public interface */ +void job_state_transition(Job *job, JobStatus s1); +int job_apply_verb(Job *job, JobVerb bv, Error **errp); + #endif diff --git a/blockjob.c b/blockjob.c index 6020a067a3..2c995d4b34 100644 --- a/blockjob.c +++ b/blockjob.c @@ -41,61 +41,6 @@ * block_job_enter. */ static QemuMutex block_job_mutex; =20 -/* BlockJob State Transition Table */ -bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] =3D { - /* U, C, R, P, Y, S, W, D, X, E,= N */ - /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0, 0, 0, 0, 0, = 0, 0}, - /* C: */ [BLOCK_JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0, 0, 0, 0, 1, = 0, 1}, - /* R: */ [BLOCK_JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1, 0, 1, 0, 1, = 0, 0}, - /* P: */ [BLOCK_JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 0, 0, 0, 0, 0, = 0, 0}, - /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 0, 0, 1, 1, 0, 1, = 0, 0}, - /* S: */ [BLOCK_JOB_STATUS_STANDBY] =3D {0, 0, 0, 0, 1, 0, 0, 0, 0, = 0, 0}, - /* W: */ [BLOCK_JOB_STATUS_WAITING] =3D {0, 0, 0, 0, 0, 0, 0, 1, 1, = 0, 0}, - /* D: */ [BLOCK_JOB_STATUS_PENDING] =3D {0, 0, 0, 0, 0, 0, 0, 0, 1, = 1, 0}, - /* X: */ [BLOCK_JOB_STATUS_ABORTING] =3D {0, 0, 0, 0, 0, 0, 0, 0, 1, = 1, 0}, - /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, = 0, 1}, - /* N: */ [BLOCK_JOB_STATUS_NULL] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, = 0, 0}, -}; - -bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] =3D { - /* U, C, R, P, Y, S, W, D, X, E,= N */ - [BLOCK_JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1, 1, 1, 1, 0, = 0, 0}, - [BLOCK_JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1, 1, 0, 0, 0, = 0, 0}, - [BLOCK_JOB_VERB_RESUME] =3D {0, 1, 1, 1, 1, 1, 0, 0, 0, = 0, 0}, - [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1, 1, 0, 0, 0, = 0, 0}, - [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1, 0, 0, 0, 0, = 0, 0}, - [BLOCK_JOB_VERB_FINALIZE] =3D {0, 0, 0, 0, 0, 0, 0, 1, 0, = 0, 0}, - [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, = 1, 0}, -}; - -static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) -{ - BlockJobStatus s0 =3D job->status; - assert(s1 >=3D 0 && s1 <=3D BLOCK_JOB_STATUS__MAX); - trace_block_job_state_transition(job, job->ret, BlockJobSTT[s0][s1] ? - "allowed" : "disallowed", - BlockJobStatus_str(s0), - BlockJobStatus_str(s1)); - assert(BlockJobSTT[s0][s1]); - job->status =3D s1; -} - -static int block_job_apply_verb(BlockJob *job, BlockJobVerb bv, Error **er= rp) -{ - assert(bv >=3D 0 && bv <=3D BLOCK_JOB_VERB__MAX); - trace_block_job_apply_verb(job, BlockJobStatus_str(job->status), - BlockJobVerb_str(bv), - BlockJobVerbTable[bv][job->status] ? - "allowed" : "prohibited"); - if (BlockJobVerbTable[bv][job->status]) { - return 0; - } - error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%= s'", - job->job.id, BlockJobStatus_str(job->status), - BlockJobVerb_str(bv)); - return -EPERM; -} - static void block_job_lock(void) { qemu_mutex_lock(&block_job_mutex); @@ -244,7 +189,7 @@ static void block_job_detach_aio_context(void *opaque); void block_job_unref(BlockJob *job) { if (--job->refcnt =3D=3D 0) { - assert(job->status =3D=3D BLOCK_JOB_STATUS_NULL); + assert(job->job.status =3D=3D JOB_STATUS_NULL); assert(!job->txn); BlockDriverState *bs =3D blk_bs(job->blk); bs->job =3D NULL; @@ -396,7 +341,7 @@ void block_job_start(BlockJob *job) job->pause_count--; job->busy =3D true; job->paused =3D false; - block_job_state_transition(job, BLOCK_JOB_STATUS_RUNNING); + job_state_transition(&job->job, JOB_STATUS_RUNNING); bdrv_coroutine_enter(blk_bs(job->blk), job->co); } =20 @@ -408,7 +353,7 @@ static void block_job_decommission(BlockJob *job) job->paused =3D false; job->deferred_to_main_loop =3D true; block_job_txn_del_job(job); - block_job_state_transition(job, BLOCK_JOB_STATUS_NULL); + job_state_transition(&job->job, JOB_STATUS_NULL); block_job_unref(job); } =20 @@ -419,7 +364,7 @@ static void block_job_do_dismiss(BlockJob *job) =20 static void block_job_conclude(BlockJob *job) { - block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED); + job_state_transition(&job->job, JOB_STATUS_CONCLUDED); if (job->auto_dismiss || !block_job_started(job)) { block_job_do_dismiss(job); } @@ -431,7 +376,7 @@ static void block_job_update_rc(BlockJob *job) job->ret =3D -ECANCELED; } if (job->ret) { - block_job_state_transition(job, BLOCK_JOB_STATUS_ABORTING); + job_state_transition(&job->job, JOB_STATUS_ABORTING); } } =20 @@ -639,7 +584,7 @@ static void block_job_completed_txn_success(BlockJob *j= ob) BlockJobTxn *txn =3D job->txn; BlockJob *other_job; =20 - block_job_state_transition(job, BLOCK_JOB_STATUS_WAITING); + job_state_transition(&job->job, JOB_STATUS_WAITING); =20 /* * Successful completion, see if there are other running jobs in this @@ -670,7 +615,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, = Error **errp) { int64_t old_speed =3D job->speed; =20 - if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) { + if (job_apply_verb(&job->job, JOB_VERB_SET_SPEED, errp)) { return; } if (speed < 0) { @@ -702,7 +647,7 @@ void block_job_complete(BlockJob *job, Error **errp) { /* Should not be reachable via external interface for internal jobs */ assert(job->job.id); - if (block_job_apply_verb(job, BLOCK_JOB_VERB_COMPLETE, errp)) { + if (job_apply_verb(&job->job, JOB_VERB_COMPLETE, errp)) { return; } if (job->pause_count || job->cancelled || !job->driver->complete) { @@ -717,7 +662,7 @@ void block_job_complete(BlockJob *job, Error **errp) void block_job_finalize(BlockJob *job, Error **errp) { assert(job && job->job.id && job->txn); - if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) { + if (job_apply_verb(&job->job, JOB_VERB_FINALIZE, errp)) { return; } block_job_do_finalize(job); @@ -728,7 +673,7 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) BlockJob *job =3D *jobptr; /* similarly to _complete, this is QMP-interface only. */ assert(job->job.id); - if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) { + if (job_apply_verb(&job->job, JOB_VERB_DISMISS, errp)) { return; } =20 @@ -738,7 +683,7 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) =20 void block_job_user_pause(BlockJob *job, Error **errp) { - if (block_job_apply_verb(job, BLOCK_JOB_VERB_PAUSE, errp)) { + if (job_apply_verb(&job->job, JOB_VERB_PAUSE, errp)) { return; } if (job->user_paused) { @@ -761,7 +706,7 @@ void block_job_user_resume(BlockJob *job, Error **errp) error_setg(errp, "Can't resume a job that was not paused"); return; } - if (block_job_apply_verb(job, BLOCK_JOB_VERB_RESUME, errp)) { + if (job_apply_verb(&job->job, JOB_VERB_RESUME, errp)) { return; } block_job_iostatus_reset(job); @@ -771,7 +716,7 @@ void block_job_user_resume(BlockJob *job, Error **errp) =20 void block_job_cancel(BlockJob *job, bool force) { - if (job->status =3D=3D BLOCK_JOB_STATUS_CONCLUDED) { + if (job->job.status =3D=3D JOB_STATUS_CONCLUDED) { block_job_do_dismiss(job); return; } @@ -787,7 +732,7 @@ void block_job_cancel(BlockJob *job, bool force) =20 void block_job_user_cancel(BlockJob *job, bool force, Error **errp) { - if (block_job_apply_verb(job, BLOCK_JOB_VERB_CANCEL, errp)) { + if (job_apply_verb(&job->job, JOB_VERB_CANCEL, errp)) { return; } block_job_cancel(job, force); @@ -852,7 +797,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **er= rp) info->speed =3D job->speed; info->io_status =3D job->iostatus; info->ready =3D job->ready; - info->status =3D job->status; + info->status =3D job->job.status; info->auto_finalize =3D job->auto_finalize; info->auto_dismiss =3D job->auto_dismiss; return info; @@ -898,7 +843,7 @@ static void block_job_event_completed(BlockJob *job, co= nst char *msg) =20 static int block_job_event_pending(BlockJob *job) { - block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING); + job_state_transition(&job->job, JOB_STATUS_PENDING); if (!job->auto_finalize && !block_job_is_internal(job)) { qapi_event_send_block_job_pending(job_type(&job->job), job->job.id, @@ -966,7 +911,6 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, job->refcnt =3D 1; job->auto_finalize =3D !(flags & BLOCK_JOB_MANUAL_FINALIZE); job->auto_dismiss =3D !(flags & BLOCK_JOB_MANUAL_DISMISS); - block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED); aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, QEMU_CLOCK_REALTIME, SCALE_NS, block_job_sleep_timer_cb, job); @@ -1008,7 +952,7 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, =20 void block_job_early_fail(BlockJob *job) { - assert(job->status =3D=3D BLOCK_JOB_STATUS_CREATED); + assert(job->job.status =3D=3D JOB_STATUS_CREATED); block_job_decommission(job); } =20 @@ -1068,14 +1012,14 @@ void coroutine_fn block_job_pause_point(BlockJob *j= ob) } =20 if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { - BlockJobStatus status =3D job->status; - block_job_state_transition(job, status =3D=3D BLOCK_JOB_STATUS_REA= DY ? \ - BLOCK_JOB_STATUS_STANDBY : \ - BLOCK_JOB_STATUS_PAUSED); + JobStatus status =3D job->job.status; + job_state_transition(&job->job, status =3D=3D JOB_STATUS_READY + ? JOB_STATUS_STANDBY + : JOB_STATUS_PAUSED); job->paused =3D true; block_job_do_yield(job, -1); job->paused =3D false; - block_job_state_transition(job, status); + job_state_transition(&job->job, status); } =20 if (job->driver->resume) { @@ -1167,7 +1111,7 @@ void block_job_iostatus_reset(BlockJob *job) =20 void block_job_event_ready(BlockJob *job) { - block_job_state_transition(job, BLOCK_JOB_STATUS_READY); + job_state_transition(&job->job, JOB_STATUS_READY); job->ready =3D true; =20 if (block_job_is_internal(job)) { diff --git a/job.c b/job.c index 00f7968c50..791776d751 100644 --- a/job.c +++ b/job.c @@ -28,9 +28,64 @@ #include "qapi/error.h" #include "qemu/job.h" #include "qemu/id.h" +#include "trace-root.h" =20 static QLIST_HEAD(, Job) jobs =3D QLIST_HEAD_INITIALIZER(jobs); =20 +/* Job State Transition Table */ +bool JobSTT[JOB_STATUS__MAX][JOB_STATUS__MAX] =3D { + /* U, C, R, P, Y, S, W, D, X, E, N */ + /* U: */ [JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* C: */ [JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1}, + /* R: */ [JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0}, + /* P: */ [JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, + /* Y: */ [JOB_STATUS_READY] =3D {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0}, + /* S: */ [JOB_STATUS_STANDBY] =3D {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, + /* W: */ [JOB_STATUS_WAITING] =3D {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, + /* D: */ [JOB_STATUS_PENDING] =3D {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, + /* X: */ [JOB_STATUS_ABORTING] =3D {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, + /* E: */ [JOB_STATUS_CONCLUDED] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + /* N: */ [JOB_STATUS_NULL] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] =3D { + /* U, C, R, P, Y, S, W, D, X, E, N */ + [JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, + [JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, + [JOB_VERB_RESUME] =3D {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, + [JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, + [JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, + [JOB_VERB_FINALIZE] =3D {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + [JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, +}; + +/* TODO Make static once the whole state machine is in job.c */ +void job_state_transition(Job *job, JobStatus s1) +{ + JobStatus s0 =3D job->status; + assert(s1 >=3D 0 && s1 <=3D JOB_STATUS__MAX); + trace_job_state_transition(job, /* TODO re-enable: job->ret */ 0, + JobSTT[s0][s1] ? "allowed" : "disallowed", + JobStatus_str(s0), JobStatus_str(s1)); + assert(JobSTT[s0][s1]); + job->status =3D s1; +} + +/* TODO Make static once the whole state machine is in job.c */ +int job_apply_verb(Job *job, JobVerb bv, Error **errp) +{ + assert(bv >=3D 0 && bv <=3D JOB_VERB__MAX); + trace_job_apply_verb(job, JobStatus_str(job->status), JobVerb_str(bv), + JobVerbTable[bv][job->status] ? + "allowed" : "prohibited"); + if (JobVerbTable[bv][job->status]) { + return 0; + } + error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%= s'", + job->id, JobStatus_str(job->status), JobVerb_str(bv)); + return -EPERM; +} + JobType job_type(Job *job) { return job->driver->job_type; @@ -81,6 +136,8 @@ void *job_create(const char *job_id, const JobDriver *dr= iver, Error **errp) job->driver =3D driver; job->id =3D g_strdup(job_id); =20 + job_state_transition(job, JOB_STATUS_CREATED); + QLIST_INSERT_HEAD(&jobs, job, job_list); =20 return job; diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index b82026180a..6ccd585dee 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -211,7 +211,7 @@ static CancelJob *create_common(BlockJob **pjob) job =3D mk_job(blk, "Steve", &test_cancel_driver, true, BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); block_job_ref(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_CREATED); + assert(job->job.status =3D=3D JOB_STATUS_CREATED); s =3D container_of(job, CancelJob, common); s->blk =3D blk; =20 @@ -223,15 +223,14 @@ static void cancel_common(CancelJob *s) { BlockJob *job =3D &s->common; BlockBackend *blk =3D s->blk; - BlockJobStatus sts =3D job->status; + JobStatus sts =3D job->job.status; =20 block_job_cancel_sync(job); - if ((sts !=3D BLOCK_JOB_STATUS_CREATED) && - (sts !=3D BLOCK_JOB_STATUS_CONCLUDED)) { + if (sts !=3D JOB_STATUS_CREATED && sts !=3D JOB_STATUS_CONCLUDED) { BlockJob *dummy =3D job; block_job_dismiss(&dummy, &error_abort); } - assert(job->status =3D=3D BLOCK_JOB_STATUS_NULL); + assert(job->job.status =3D=3D JOB_STATUS_NULL); block_job_unref(job); destroy_blk(blk); } @@ -253,7 +252,7 @@ static void test_cancel_running(void) s =3D create_common(&job); =20 block_job_start(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_RUNNING); + assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 cancel_common(s); } @@ -266,11 +265,11 @@ static void test_cancel_paused(void) s =3D create_common(&job); =20 block_job_start(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_RUNNING); + assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 block_job_user_pause(job, &error_abort); block_job_enter(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_PAUSED); + assert(job->job.status =3D=3D JOB_STATUS_PAUSED); =20 cancel_common(s); } @@ -283,11 +282,11 @@ static void test_cancel_ready(void) s =3D create_common(&job); =20 block_job_start(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_RUNNING); + assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; block_job_enter(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_READY); + assert(job->job.status =3D=3D JOB_STATUS_READY); =20 cancel_common(s); } @@ -300,15 +299,15 @@ static void test_cancel_standby(void) s =3D create_common(&job); =20 block_job_start(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_RUNNING); + assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; block_job_enter(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_READY); + assert(job->job.status =3D=3D JOB_STATUS_READY); =20 block_job_user_pause(job, &error_abort); block_job_enter(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_STANDBY); + assert(job->job.status =3D=3D JOB_STATUS_STANDBY); =20 cancel_common(s); } @@ -321,18 +320,18 @@ static void test_cancel_pending(void) s =3D create_common(&job); =20 block_job_start(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_RUNNING); + assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; block_job_enter(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_READY); + assert(job->job.status =3D=3D JOB_STATUS_READY); =20 block_job_complete(job, &error_abort); block_job_enter(job); while (!s->completed) { aio_poll(qemu_get_aio_context(), true); } - assert(job->status =3D=3D BLOCK_JOB_STATUS_PENDING); + assert(job->job.status =3D=3D JOB_STATUS_PENDING); =20 cancel_common(s); } @@ -345,21 +344,21 @@ static void test_cancel_concluded(void) s =3D create_common(&job); =20 block_job_start(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_RUNNING); + assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; block_job_enter(job); - assert(job->status =3D=3D BLOCK_JOB_STATUS_READY); + assert(job->job.status =3D=3D JOB_STATUS_READY); =20 block_job_complete(job, &error_abort); block_job_enter(job); while (!s->completed) { aio_poll(qemu_get_aio_context(), true); } - assert(job->status =3D=3D BLOCK_JOB_STATUS_PENDING); + assert(job->job.status =3D=3D JOB_STATUS_PENDING); =20 block_job_finalize(job, &error_abort); - assert(job->status =3D=3D BLOCK_JOB_STATUS_CONCLUDED); + assert(job->job.status =3D=3D JOB_STATUS_CONCLUDED); =20 cancel_common(s); } diff --git a/block/trace-events b/block/trace-events index f8c50b4063..93b927908a 100644 --- a/block/trace-events +++ b/block/trace-events @@ -6,8 +6,6 @@ bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" =20 # blockjob.c block_job_completed(void *job, int ret, int jret) "job %p ret %d corrected= ret %d" -block_job_state_transition(void *job, int ret, const char *legal, const c= har *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%= s)" -block_job_apply_verb(void *job, const char *state, const char *verb, const= char *legal) "job %p in state %s; applying verb %s (%s)" =20 # block/block-backend.c blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int= flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x" diff --git a/trace-events b/trace-events index ed71f44649..2507e1327d 100644 --- a/trace-events +++ b/trace-events @@ -104,6 +104,10 @@ gdbstub_err_invalid_rle(void) "got invalid RLE sequenc= e" gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum dig= it: 0x%02x" gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command= packet with incorrect checksum, expected=3D0x%02x, received=3D0x%02x" =20 +# job.c +job_state_transition(void *job, int ret, const char *legal, const char *s= 0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" +job_apply_verb(void *job, const char *state, const char *verb, const char = *legal) "job %p in state %s; applying verb %s (%s)" + ### Guest events, keep at bottom =20 =20 --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585097174311.5688813414521; Tue, 24 Apr 2018 08:51:37 -0700 (PDT) Received: from localhost ([::1]:59239 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0EC-00031D-BH for importer@patchew.org; Tue, 24 Apr 2018 11:51:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47808) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpD-00081b-JU for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpB-00088D-5E for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:47 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34842 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzp6-000817-4h; Tue, 24 Apr 2018 11:25:40 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A81CE738E0; Tue, 24 Apr 2018 15:25:39 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 97C2B2026990; Tue, 24 Apr 2018 15:25:38 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:55 +0200 Message-Id: <20180424152515.25664-14-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:39 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:39 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 13/33] job: Add reference counting X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves reference counting from BlockJob to Job. In order to keep calling the BlockJob cleanup code when the job is deleted via job_unref(), introduce a new JobDriver.free callback. Every block job must use block_job_free() for this callback, this is asserted in block_job_create(). Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 21 ------------------- include/block/blockjob_int.h | 7 +++++++ include/qemu/job.h | 19 ++++++++++++++++-- block/backup.c | 1 + block/commit.c | 1 + block/mirror.c | 2 ++ block/stream.c | 1 + blockjob.c | 48 +++++++++++++++++++---------------------= ---- job.c | 22 ++++++++++++++++---- qemu-img.c | 4 ++-- tests/test-bdrv-drain.c | 1 + tests/test-blockjob-txn.c | 1 + tests/test-blockjob.c | 6 ++++-- 13 files changed, 76 insertions(+), 58 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 96e5f67ed7..5e32e719b6 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -132,9 +132,6 @@ typedef struct BlockJob { /** The opaque value that is passed to the completion function. */ void *opaque; =20 - /** Reference count of the block job */ - int refcnt; - /** True when job has reported completion by calling block_job_complet= ed. */ bool completed; =20 @@ -400,24 +397,6 @@ void block_job_iostatus_reset(BlockJob *job); BlockJobTxn *block_job_txn_new(void); =20 /** - * block_job_ref: - * - * Add a reference to BlockJob refcnt, it will be decreased with - * block_job_unref, and then be freed if it comes to be the last - * reference. - */ -void block_job_ref(BlockJob *job); - -/** - * block_job_unref: - * - * Release a reference that was previously acquired with block_job_ref - * or block_job_create. If it's the last reference to the object, it will = be - * freed. - */ -void block_job_unref(BlockJob *job); - -/** * block_job_txn_unref: * * Release a reference that was previously acquired with block_job_txn_add= _job diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 699a6d1487..4e95fa9f24 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -144,6 +144,13 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, BlockCompletionFunc *cb, void *opaque, Error **errp= ); =20 /** + * block_job_free: + * Callback to be used for JobDriver.free in all block jobs. Frees block j= ob + * specific resources in @job. + */ +void block_job_free(Job *job); + +/** * block_job_sleep_ns: * @job: The job that calls the function. * @ns: How many nanoseconds to stop for. diff --git a/include/qemu/job.h b/include/qemu/job.h index c22054a7be..f502c30620 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -41,6 +41,9 @@ typedef struct Job { /** The type of this job. */ const JobDriver *driver; =20 + /** Reference count of the block job */ + int refcnt; + /** Current state; See @JobStatus for details. */ JobStatus status; =20 @@ -57,6 +60,9 @@ struct JobDriver { =20 /** Enum describing the operation */ JobType job_type; + + /** Called when the job is freed */ + void (*free)(Job *job); }; =20 =20 @@ -69,8 +75,17 @@ struct JobDriver { */ void *job_create(const char *job_id, const JobDriver *driver, Error **errp= ); =20 -/** Frees the @job object. */ -void job_delete(Job *job); +/** + * Add a reference to Job refcnt, it will be decreased with job_unref, and= then + * be freed if it comes to be the last reference. + */ +void job_ref(Job *job); + +/** + * Release a reference that was previously acquired with job_ref() or + * job_create(). If it's the last reference to the object, it will be free= d. + */ +void job_unref(Job *job); =20 /** Returns the JobType of a given Job. */ JobType job_type(Job *job); diff --git a/block/backup.c b/block/backup.c index 780c2bde90..569a118448 100644 --- a/block/backup.c +++ b/block/backup.c @@ -526,6 +526,7 @@ static const BlockJobDriver backup_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(BackupBlockJob), .job_type =3D JOB_TYPE_BACKUP, + .free =3D block_job_free, }, .start =3D backup_run, .commit =3D backup_commit, diff --git a/block/commit.c b/block/commit.c index 32d29c890e..925c96abe7 100644 --- a/block/commit.c +++ b/block/commit.c @@ -218,6 +218,7 @@ static const BlockJobDriver commit_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(CommitBlockJob), .job_type =3D JOB_TYPE_COMMIT, + .free =3D block_job_free, }, .start =3D commit_run, }; diff --git a/block/mirror.c b/block/mirror.c index 2c014a2b96..6ff8a370a5 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -985,6 +985,7 @@ static const BlockJobDriver mirror_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), .job_type =3D JOB_TYPE_MIRROR, + .free =3D block_job_free, }, .start =3D mirror_run, .complete =3D mirror_complete, @@ -997,6 +998,7 @@ static const BlockJobDriver commit_active_job_driver = =3D { .job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), .job_type =3D JOB_TYPE_COMMIT, + .free =3D block_job_free, }, .start =3D mirror_run, .complete =3D mirror_complete, diff --git a/block/stream.c b/block/stream.c index cb723f190a..7273d2213c 100644 --- a/block/stream.c +++ b/block/stream.c @@ -212,6 +212,7 @@ static const BlockJobDriver stream_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(StreamBlockJob), .job_type =3D JOB_TYPE_STREAM, + .free =3D block_job_free, }, .start =3D stream_run, }; diff --git a/blockjob.c b/blockjob.c index 2c995d4b34..34bc431696 100644 --- a/blockjob.c +++ b/blockjob.c @@ -177,31 +177,25 @@ static void block_job_resume(BlockJob *job) block_job_enter(job); } =20 -void block_job_ref(BlockJob *job) -{ - ++job->refcnt; -} - static void block_job_attached_aio_context(AioContext *new_context, void *opaque); static void block_job_detach_aio_context(void *opaque); =20 -void block_job_unref(BlockJob *job) +void block_job_free(Job *job) { - if (--job->refcnt =3D=3D 0) { - assert(job->job.status =3D=3D JOB_STATUS_NULL); - assert(!job->txn); - BlockDriverState *bs =3D blk_bs(job->blk); - bs->job =3D NULL; - block_job_remove_all_bdrv(job); - blk_remove_aio_context_notifier(job->blk, - block_job_attached_aio_context, - block_job_detach_aio_context, job); - blk_unref(job->blk); - error_free(job->blocker); - assert(!timer_pending(&job->sleep_timer)); - job_delete(&job->job); - } + BlockJob *bjob =3D container_of(job, BlockJob, job); + BlockDriverState *bs =3D blk_bs(bjob->blk); + + assert(!bjob->txn); + + bs->job =3D NULL; + block_job_remove_all_bdrv(bjob); + blk_remove_aio_context_notifier(bjob->blk, + block_job_attached_aio_context, + block_job_detach_aio_context, bjob); + blk_unref(bjob->blk); + error_free(bjob->blocker); + assert(!timer_pending(&bjob->sleep_timer)); } =20 static void block_job_attached_aio_context(AioContext *new_context, @@ -232,7 +226,7 @@ static void block_job_detach_aio_context(void *opaque) BlockJob *job =3D opaque; =20 /* In case the job terminates during aio_poll()... */ - block_job_ref(job); + job_ref(&job->job); =20 block_job_pause(job); =20 @@ -240,7 +234,7 @@ static void block_job_detach_aio_context(void *opaque) block_job_drain(job); } =20 - block_job_unref(job); + job_unref(&job->job); } =20 static char *child_job_get_parent_desc(BdrvChild *c) @@ -354,7 +348,7 @@ static void block_job_decommission(BlockJob *job) job->deferred_to_main_loop =3D true; block_job_txn_del_job(job); job_state_transition(&job->job, JOB_STATUS_NULL); - block_job_unref(job); + job_unref(&job->job); } =20 static void block_job_do_dismiss(BlockJob *job) @@ -493,14 +487,14 @@ static int block_job_finish_sync(BlockJob *job, =20 assert(blk_bs(job->blk)->job =3D=3D job); =20 - block_job_ref(job); + job_ref(&job->job); =20 if (finish) { finish(job, &local_err); } if (local_err) { error_propagate(errp, local_err); - block_job_unref(job); + job_unref(&job->job); return -EBUSY; } /* block_job_drain calls block_job_enter, and it should be enough to @@ -513,7 +507,7 @@ static int block_job_finish_sync(BlockJob *job, aio_poll(qemu_get_aio_context(), true); } ret =3D (job->cancelled && job->ret =3D=3D 0) ? -ECANCELED : job->ret; - block_job_unref(job); + job_unref(&job->job); return ret; } =20 @@ -900,6 +894,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, } =20 assert(is_block_job(&job->job)); + assert(job->job.driver->free =3D=3D &block_job_free); =20 job->driver =3D driver; job->blk =3D blk; @@ -908,7 +903,6 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, job->busy =3D false; job->paused =3D true; job->pause_count =3D 1; - job->refcnt =3D 1; job->auto_finalize =3D !(flags & BLOCK_JOB_MANUAL_FINALIZE); job->auto_dismiss =3D !(flags & BLOCK_JOB_MANUAL_DISMISS); aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, diff --git a/job.c b/job.c index 791776d751..bcf5d5c288 100644 --- a/job.c +++ b/job.c @@ -135,6 +135,7 @@ void *job_create(const char *job_id, const JobDriver *d= river, Error **errp) job =3D g_malloc0(driver->instance_size); job->driver =3D driver; job->id =3D g_strdup(job_id); + job->refcnt =3D 1; =20 job_state_transition(job, JOB_STATUS_CREATED); =20 @@ -143,10 +144,23 @@ void *job_create(const char *job_id, const JobDriver = *driver, Error **errp) return job; } =20 -void job_delete(Job *job) +void job_ref(Job *job) { - QLIST_REMOVE(job, job_list); + ++job->refcnt; +} + +void job_unref(Job *job) +{ + if (--job->refcnt =3D=3D 0) { + assert(job->status =3D=3D JOB_STATUS_NULL); =20 - g_free(job->id); - g_free(job); + if (job->driver->free) { + job->driver->free(job); + } + + QLIST_REMOVE(job, job_list); + + g_free(job->id); + g_free(job); + } } diff --git a/qemu-img.c b/qemu-img.c index 855fa52514..62a52edc34 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -862,7 +862,7 @@ static void run_block_job(BlockJob *job, Error **errp) int ret =3D 0; =20 aio_context_acquire(aio_context); - block_job_ref(job); + job_ref(&job->job); do { aio_poll(aio_context, true); qemu_progress_print(job->len ? @@ -874,7 +874,7 @@ static void run_block_job(BlockJob *job, Error **errp) } else { ret =3D job->ret; } - block_job_unref(job); + job_unref(&job->job); aio_context_release(aio_context); =20 /* publish completion progress only when success */ diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index fe9f412b39..f9e37d479c 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -522,6 +522,7 @@ static void test_job_complete(BlockJob *job, Error **er= rp) BlockJobDriver test_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(TestBlockJob), + .free =3D block_job_free, }, .start =3D test_job_start, .complete =3D test_job_complete, diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 48b12d1744..b49b28ca27 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -76,6 +76,7 @@ static void test_block_job_cb(void *opaque, int ret) static const BlockJobDriver test_block_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(TestBlockJob), + .free =3D block_job_free, }, .start =3D test_block_job_run, }; diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 6ccd585dee..e24fc3f140 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -19,6 +19,7 @@ static const BlockJobDriver test_block_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(BlockJob), + .free =3D block_job_free, }, }; =20 @@ -196,6 +197,7 @@ static void coroutine_fn cancel_job_start(void *opaque) static const BlockJobDriver test_cancel_driver =3D { .job_driver =3D { .instance_size =3D sizeof(CancelJob), + .free =3D block_job_free, }, .start =3D cancel_job_start, .complete =3D cancel_job_complete, @@ -210,7 +212,7 @@ static CancelJob *create_common(BlockJob **pjob) blk =3D create_blk(NULL); job =3D mk_job(blk, "Steve", &test_cancel_driver, true, BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); - block_job_ref(job); + job_ref(&job->job); assert(job->job.status =3D=3D JOB_STATUS_CREATED); s =3D container_of(job, CancelJob, common); s->blk =3D blk; @@ -231,7 +233,7 @@ static void cancel_common(CancelJob *s) block_job_dismiss(&dummy, &error_abort); } assert(job->job.status =3D=3D JOB_STATUS_NULL); - block_job_unref(job); + job_unref(&job->job); destroy_blk(blk); } =20 --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584701348330.9228896249234; Tue, 24 Apr 2018 08:45:01 -0700 (PDT) Received: from localhost ([::1]:59195 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB07k-0006AG-KE for importer@patchew.org; Tue, 24 Apr 2018 11:44:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47862) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpG-00085f-9g for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpD-0008AQ-Ds for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:50 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59834 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzp7-00082p-Bs; Tue, 24 Apr 2018 11:25:41 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id F253F406C7A0; Tue, 24 Apr 2018 15:25:40 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id E32B7202342F; Tue, 24 Apr 2018 15:25:39 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:56 +0200 Message-Id: <20180424152515.25664-15-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:41 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:41 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 14/33] job: Move cancelled to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We cannot yet move the whole logic around job cancelling to Job because it depends on quite a few other things that are still only in BlockJob, but we can move the cancelled field at least. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 8 -------- include/block/blockjob_int.h | 8 -------- include/qemu/job.h | 11 +++++++++++ block/backup.c | 6 +++--- block/commit.c | 4 ++-- block/mirror.c | 20 ++++++++++---------- block/stream.c | 4 ++-- blockjob.c | 28 +++++++++++++--------------- job.c | 5 +++++ tests/test-blockjob-txn.c | 6 +++--- tests/test-blockjob.c | 2 +- 11 files changed, 50 insertions(+), 52 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 5e32e719b6..04efc94ffc 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -57,14 +57,6 @@ typedef struct BlockJob { Coroutine *co; =20 /** - * Set to true if the job should cancel itself. The flag must - * always be tested just before toggling the busy flag from false - * to true. After a job has been cancelled, it should only yield - * if #aio_poll will ("sooner or later") reenter the coroutine. - */ - bool cancelled; - - /** * Set to true if the job should abort immediately without waiting * for data to be in sync. */ diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 4e95fa9f24..e9790e9a0d 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -196,14 +196,6 @@ void block_job_early_fail(BlockJob *job); void block_job_completed(BlockJob *job, int ret); =20 /** - * block_job_is_cancelled: - * @job: The job being queried. - * - * Returns whether the job is scheduled for cancellation. - */ -bool block_job_is_cancelled(BlockJob *job); - -/** * block_job_pause_point: * @job: The job that is ready to pause. * diff --git a/include/qemu/job.h b/include/qemu/job.h index f502c30620..741bf2628d 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -47,6 +47,14 @@ typedef struct Job { /** Current state; See @JobStatus for details. */ JobStatus status; =20 + /** + * Set to true if the job should cancel itself. The flag must + * always be tested just before toggling the busy flag from false + * to true. After a job has been cancelled, it should only yield + * if #aio_poll will ("sooner or later") reenter the coroutine. + */ + bool cancelled; + /** Element of the list of jobs */ QLIST_ENTRY(Job) job_list; } Job; @@ -93,6 +101,9 @@ JobType job_type(Job *job); /** Returns the enum string for the JobType of a given Job. */ const char *job_type_str(Job *job); =20 +/** Returns whether the job is scheduled for cancellation. */ +bool job_is_cancelled(Job *job); + /** * Get the next element from the list of block jobs after @job, or the * first one if @job is %NULL. diff --git a/block/backup.c b/block/backup.c index 569a118448..1d330b7266 100644 --- a/block/backup.c +++ b/block/backup.c @@ -329,7 +329,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob= *job) { uint64_t delay_ns; =20 - if (block_job_is_cancelled(&job->common)) { + if (job_is_cancelled(&job->common.job)) { return true; } =20 @@ -339,7 +339,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob= *job) job->bytes_read =3D 0; block_job_sleep_ns(&job->common, delay_ns); =20 - if (block_job_is_cancelled(&job->common)) { + if (job_is_cancelled(&job->common.job)) { return true; } =20 @@ -441,7 +441,7 @@ static void coroutine_fn backup_run(void *opaque) if (job->sync_mode =3D=3D MIRROR_SYNC_MODE_NONE) { /* All bits are set in copy_bitmap to allow any cluster to be copi= ed. * This does not actually require them to be copied. */ - while (!block_job_is_cancelled(&job->common)) { + while (!job_is_cancelled(&job->common.job)) { /* Yield until the job is cancelled. We just let our before_w= rite * notify callback service CoW requests. */ block_job_yield(&job->common); diff --git a/block/commit.c b/block/commit.c index 925c96abe7..85baea8f92 100644 --- a/block/commit.c +++ b/block/commit.c @@ -90,7 +90,7 @@ static void commit_complete(BlockJob *job, void *opaque) * the normal backing chain can be restored. */ blk_unref(s->base); =20 - if (!block_job_is_cancelled(&s->common) && ret =3D=3D 0) { + if (!job_is_cancelled(&s->common.job) && ret =3D=3D 0) { /* success */ ret =3D bdrv_drop_intermediate(s->commit_top_bs, base, s->backing_file_str); @@ -172,7 +172,7 @@ static void coroutine_fn commit_run(void *opaque) * with no pending I/O here so that bdrv_drain_all() returns. */ block_job_sleep_ns(&s->common, delay_ns); - if (block_job_is_cancelled(&s->common)) { + if (job_is_cancelled(&s->common.job)) { break; } /* Copy if allocated above the base */ diff --git a/block/mirror.c b/block/mirror.c index 6ff8a370a5..937b915268 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -622,7 +622,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJo= b *s) =20 mirror_throttle(s); =20 - if (block_job_is_cancelled(&s->common)) { + if (job_is_cancelled(&s->common.job)) { s->initial_zeroing_ongoing =3D false; return 0; } @@ -650,7 +650,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJo= b *s) =20 mirror_throttle(s); =20 - if (block_job_is_cancelled(&s->common)) { + if (job_is_cancelled(&s->common.job)) { return 0; } =20 @@ -695,7 +695,7 @@ static void coroutine_fn mirror_run(void *opaque) checking for a NULL string */ int ret =3D 0; =20 - if (block_job_is_cancelled(&s->common)) { + if (job_is_cancelled(&s->common.job)) { goto immediate_exit; } =20 @@ -729,10 +729,10 @@ static void coroutine_fn mirror_run(void *opaque) /* Report BLOCK_JOB_READY and wait for complete. */ block_job_event_ready(&s->common); s->synced =3D true; - while (!block_job_is_cancelled(&s->common) && !s->should_complete)= { + while (!job_is_cancelled(&s->common.job) && !s->should_complete) { block_job_yield(&s->common); } - s->common.cancelled =3D false; + s->common.job.cancelled =3D false; goto immediate_exit; } =20 @@ -768,7 +768,7 @@ static void coroutine_fn mirror_run(void *opaque) s->last_pause_ns =3D qemu_clock_get_ns(QEMU_CLOCK_REALTIME); if (!s->is_none_mode) { ret =3D mirror_dirty_init(s); - if (ret < 0 || block_job_is_cancelled(&s->common)) { + if (ret < 0 || job_is_cancelled(&s->common.job)) { goto immediate_exit; } } @@ -829,7 +829,7 @@ static void coroutine_fn mirror_run(void *opaque) } =20 should_complete =3D s->should_complete || - block_job_is_cancelled(&s->common); + job_is_cancelled(&s->common.job); cnt =3D bdrv_get_dirty_count(s->dirty_bitmap); } =20 @@ -857,14 +857,14 @@ static void coroutine_fn mirror_run(void *opaque) * completion. */ assert(QLIST_EMPTY(&bs->tracked_requests)); - s->common.cancelled =3D false; + s->common.job.cancelled =3D false; need_drain =3D false; break; } =20 ret =3D 0; trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); - if (block_job_is_cancelled(&s->common) && s->common.force) { + if (job_is_cancelled(&s->common.job) && s->common.force) { break; } else if (!should_complete) { delay_ns =3D (s->in_flight =3D=3D 0 && cnt =3D=3D 0 ? SLICE_TI= ME : 0); @@ -880,7 +880,7 @@ immediate_exit: * the target is a copy of the source. */ assert(ret < 0 || ((s->common.force || !s->synced) && - block_job_is_cancelled(&s->common))); + job_is_cancelled(&s->common.job))); assert(need_drain); mirror_wait_for_all_io(s); } diff --git a/block/stream.c b/block/stream.c index 7273d2213c..22c71ae100 100644 --- a/block/stream.c +++ b/block/stream.c @@ -66,7 +66,7 @@ static void stream_complete(BlockJob *job, void *opaque) BlockDriverState *base =3D s->base; Error *local_err =3D NULL; =20 - if (!block_job_is_cancelled(&s->common) && bs->backing && + if (!job_is_cancelled(&s->common.job) && bs->backing && data->ret =3D=3D 0) { const char *base_id =3D NULL, *base_fmt =3D NULL; if (base) { @@ -141,7 +141,7 @@ static void coroutine_fn stream_run(void *opaque) * with no pending I/O here so that bdrv_drain_all() returns. */ block_job_sleep_ns(&s->common, delay_ns); - if (block_job_is_cancelled(&s->common)) { + if (job_is_cancelled(&s->common.job)) { break; } =20 diff --git a/blockjob.c b/blockjob.c index 34bc431696..d7d9744db7 100644 --- a/blockjob.c +++ b/blockjob.c @@ -366,7 +366,7 @@ static void block_job_conclude(BlockJob *job) =20 static void block_job_update_rc(BlockJob *job) { - if (!job->ret && block_job_is_cancelled(job)) { + if (!job->ret && job_is_cancelled(&job->job)) { job->ret =3D -ECANCELED; } if (job->ret) { @@ -425,7 +425,7 @@ static int block_job_finalize_single(BlockJob *job) =20 /* Emit events only if we actually started */ if (block_job_started(job)) { - if (block_job_is_cancelled(job)) { + if (job_is_cancelled(&job->job)) { block_job_event_cancelled(job); } else { const char *msg =3D NULL; @@ -451,7 +451,7 @@ static void block_job_cancel_async(BlockJob *job, bool = force) job->user_paused =3D false; job->pause_count--; } - job->cancelled =3D true; + job->job.cancelled =3D true; /* To prevent 'force =3D=3D false' overriding a previous 'force =3D=3D= true' */ job->force |=3D force; } @@ -506,7 +506,8 @@ static int block_job_finish_sync(BlockJob *job, while (!job->completed) { aio_poll(qemu_get_aio_context(), true); } - ret =3D (job->cancelled && job->ret =3D=3D 0) ? -ECANCELED : job->ret; + ret =3D (job_is_cancelled(&job->job) && job->ret =3D=3D 0) + ? -ECANCELED : job->ret; job_unref(&job->job); return ret; } @@ -544,7 +545,7 @@ static void block_job_completed_txn_abort(BlockJob *job) other_job =3D QLIST_FIRST(&txn->jobs); ctx =3D blk_get_aio_context(other_job->blk); if (!other_job->completed) { - assert(other_job->cancelled); + assert(job_is_cancelled(&other_job->job)); block_job_finish_sync(other_job, NULL, NULL); } block_job_finalize_single(other_job); @@ -644,7 +645,9 @@ void block_job_complete(BlockJob *job, Error **errp) if (job_apply_verb(&job->job, JOB_VERB_COMPLETE, errp)) { return; } - if (job->pause_count || job->cancelled || !job->driver->complete) { + if (job->pause_count || job_is_cancelled(&job->job) || + !job->driver->complete) + { error_setg(errp, "The active block job '%s' cannot be completed", job->job.id); return; @@ -997,7 +1000,7 @@ void coroutine_fn block_job_pause_point(BlockJob *job) if (!block_job_should_pause(job)) { return; } - if (block_job_is_cancelled(job)) { + if (job_is_cancelled(&job->job)) { return; } =20 @@ -1005,7 +1008,7 @@ void coroutine_fn block_job_pause_point(BlockJob *job) job->driver->pause(job); } =20 - if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { + if (block_job_should_pause(job) && !job_is_cancelled(&job->job)) { JobStatus status =3D job->job.status; job_state_transition(&job->job, status =3D=3D JOB_STATUS_READY ? JOB_STATUS_STANDBY @@ -1057,17 +1060,12 @@ void block_job_enter(BlockJob *job) block_job_enter_cond(job, NULL); } =20 -bool block_job_is_cancelled(BlockJob *job) -{ - return job->cancelled; -} - void block_job_sleep_ns(BlockJob *job, int64_t ns) { assert(job->busy); =20 /* Check cancellation *before* setting busy =3D false, too! */ - if (block_job_is_cancelled(job)) { + if (job_is_cancelled(&job->job)) { return; } =20 @@ -1083,7 +1081,7 @@ void block_job_yield(BlockJob *job) assert(job->busy); =20 /* Check cancellation *before* setting busy =3D false, too! */ - if (block_job_is_cancelled(job)) { + if (job_is_cancelled(&job->job)) { return; } =20 diff --git a/job.c b/job.c index bcf5d5c288..f7b9ef9e4b 100644 --- a/job.c +++ b/job.c @@ -96,6 +96,11 @@ const char *job_type_str(Job *job) return JobType_str(job_type(job)); } =20 +bool job_is_cancelled(Job *job) +{ + return job->cancelled; +} + Job *job_next(Job *job) { if (!job) { diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index b49b28ca27..26b4bbb230 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -29,7 +29,7 @@ static void test_block_job_complete(BlockJob *job, void *= opaque) BlockDriverState *bs =3D blk_bs(job->blk); int rc =3D (intptr_t)opaque; =20 - if (block_job_is_cancelled(job)) { + if (job_is_cancelled(&job->job)) { rc =3D -ECANCELED; } =20 @@ -49,7 +49,7 @@ static void coroutine_fn test_block_job_run(void *opaque) block_job_yield(job); } =20 - if (block_job_is_cancelled(job)) { + if (job_is_cancelled(&job->job)) { break; } } @@ -66,7 +66,7 @@ typedef struct { static void test_block_job_cb(void *opaque, int ret) { TestBlockJobCBData *data =3D opaque; - if (!ret && block_job_is_cancelled(&data->job->common)) { + if (!ret && job_is_cancelled(&data->job->common.job)) { ret =3D -ECANCELED; } *data->result =3D ret; diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index e24fc3f140..fa31481537 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -179,7 +179,7 @@ static void coroutine_fn cancel_job_start(void *opaque) CancelJob *s =3D opaque; =20 while (!s->should_complete) { - if (block_job_is_cancelled(&s->common)) { + if (job_is_cancelled(&s->common.job)) { goto defer; } =20 --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524586076172160.58864147689667; Tue, 24 Apr 2018 09:07:56 -0700 (PDT) Received: from localhost ([::1]:59353 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Tz-00084D-8n for importer@patchew.org; Tue, 24 Apr 2018 12:07:55 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47794) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpC-00080p-Vi for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpB-00088c-RU for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:46 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34844 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzp9-00085B-1i; Tue, 24 Apr 2018 11:25:43 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 86A22FB674; Tue, 24 Apr 2018 15:25:42 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3959E202342F; Tue, 24 Apr 2018 15:25:41 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:57 +0200 Message-Id: <20180424152515.25664-16-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:42 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:42 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 15/33] job: Add Job.aio_context X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" When block jobs need an AioContext, they just take it from their main block node. Generic jobs don't have a main block node, so we need to assign them an AioContext explicitly. Signed-off-by: Kevin Wolf --- include/qemu/job.h | 7 ++++++- blockjob.c | 5 ++++- job.c | 4 +++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/qemu/job.h b/include/qemu/job.h index 741bf2628d..c1882bb0dd 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -47,6 +47,9 @@ typedef struct Job { /** Current state; See @JobStatus for details. */ JobStatus status; =20 + /** AioContext to run the job coroutine in */ + AioContext *aio_context; + /** * Set to true if the job should cancel itself. The flag must * always be tested just before toggling the busy flag from false @@ -79,9 +82,11 @@ struct JobDriver { * * @job_id: The id of the newly-created job, or %NULL for internal jobs * @driver: The class object for the newly-created job. + * @ctx: The AioContext to run the job coroutine in. * @errp: Error object. */ -void *job_create(const char *job_id, const JobDriver *driver, Error **errp= ); +void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, + Error **errp); =20 /** * Add a reference to Job refcnt, it will be decreased with job_unref, and= then diff --git a/blockjob.c b/blockjob.c index d7d9744db7..734dd168dd 100644 --- a/blockjob.c +++ b/blockjob.c @@ -203,6 +203,7 @@ static void block_job_attached_aio_context(AioContext *= new_context, { BlockJob *job =3D opaque; =20 + job->job.aio_context =3D new_context; if (job->driver->attached_aio_context) { job->driver->attached_aio_context(job, new_context); } @@ -234,6 +235,7 @@ static void block_job_detach_aio_context(void *opaque) block_job_drain(job); } =20 + job->job.aio_context =3D NULL; job_unref(&job->job); } =20 @@ -890,7 +892,8 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, return NULL; } =20 - job =3D job_create(job_id, &driver->job_driver, errp); + job =3D job_create(job_id, &driver->job_driver, blk_get_aio_context(bl= k), + errp); if (job =3D=3D NULL) { blk_unref(blk); return NULL; diff --git a/job.c b/job.c index f7b9ef9e4b..a28a7765e5 100644 --- a/job.c +++ b/job.c @@ -122,7 +122,8 @@ Job *job_get(const char *id) return NULL; } =20 -void *job_create(const char *job_id, const JobDriver *driver, Error **errp) +void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, + Error **errp) { Job *job; =20 @@ -141,6 +142,7 @@ void *job_create(const char *job_id, const JobDriver *d= river, Error **errp) job->driver =3D driver; job->id =3D g_strdup(job_id); job->refcnt =3D 1; + job->aio_context =3D ctx; =20 job_state_transition(job, JOB_STATUS_CREATED); =20 --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585296255188.58930779459445; Tue, 24 Apr 2018 08:54:56 -0700 (PDT) Received: from localhost ([::1]:59259 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0HP-0005l8-9q for importer@patchew.org; Tue, 24 Apr 2018 11:54:55 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47936) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpJ-00087z-KB for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpG-0008EX-4y for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:53 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:58900 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpA-00087G-6X; Tue, 24 Apr 2018 11:25:44 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D250440201DF; Tue, 24 Apr 2018 15:25:43 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id C1FC02026990; Tue, 24 Apr 2018 15:25:42 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:58 +0200 Message-Id: <20180424152515.25664-17-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 24 Apr 2018 15:25:43 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 24 Apr 2018 15:25:43 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 16/33] job: Move defer_to_main_loop to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 5 ---- include/block/blockjob_int.h | 19 --------------- include/qemu/job.h | 20 ++++++++++++++++ block/backup.c | 7 +++--- block/commit.c | 11 +++++---- block/mirror.c | 15 ++++++------ block/stream.c | 14 +++++------ blockjob.c | 57 ++++------------------------------------= ---- job.c | 33 +++++++++++++++++++++++++ tests/test-bdrv-drain.c | 7 +++--- tests/test-blockjob-txn.c | 13 +++++----- tests/test-blockjob.c | 7 +++--- 12 files changed, 98 insertions(+), 110 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 04efc94ffc..90942826f5 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -92,11 +92,6 @@ typedef struct BlockJob { */ bool ready; =20 - /** - * Set to true when the job has deferred work to the main loop. - */ - bool deferred_to_main_loop; - /** Status that is published by the query-block-jobs QMP API */ BlockDeviceIoStatus iostatus; =20 diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index e9790e9a0d..b0338282c8 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -233,23 +233,4 @@ void block_job_event_ready(BlockJob *job); BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_= err, int is_read, int error); =20 -typedef void BlockJobDeferToMainLoopFn(BlockJob *job, void *opaque); - -/** - * block_job_defer_to_main_loop: - * @job: The job - * @fn: The function to run in the main loop - * @opaque: The opaque value that is passed to @fn - * - * This function must be called by the main job coroutine just before it - * returns. @fn is executed in the main loop with the BlockDriverState - * AioContext acquired. Block jobs must call bdrv_unref(), bdrv_close(), = and - * anything that uses bdrv_drain_all() in the main loop. - * - * The @job AioContext is held while @fn executes. - */ -void block_job_defer_to_main_loop(BlockJob *job, - BlockJobDeferToMainLoopFn *fn, - void *opaque); - #endif diff --git a/include/qemu/job.h b/include/qemu/job.h index c1882bb0dd..63a40b2714 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -58,6 +58,9 @@ typedef struct Job { */ bool cancelled; =20 + /** Set to true when the job has deferred work to the main loop. */ + bool deferred_to_main_loop; + /** Element of the list of jobs */ QLIST_ENTRY(Job) job_list; } Job; @@ -124,6 +127,23 @@ Job *job_next(Job *job); */ Job *job_get(const char *id); =20 +typedef void JobDeferToMainLoopFn(Job *job, void *opaque); + +/** + * @job: The job + * @fn: The function to run in the main loop + * @opaque: The opaque value that is passed to @fn + * + * This function must be called by the main job coroutine just before it + * returns. @fn is executed in the main loop with the job AioContext acqu= ired. + * + * Block jobs must call bdrv_unref(), bdrv_close(), and anything that uses + * bdrv_drain_all() in the main loop. + * + * The @job AioContext is held while @fn executes. + */ +void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaq= ue); + /* TODO To be removed from the public interface */ void job_state_transition(Job *job, JobStatus s1); int job_apply_verb(Job *job, JobVerb bv, Error **errp); diff --git a/block/backup.c b/block/backup.c index 1d330b7266..ce9cc01617 100644 --- a/block/backup.c +++ b/block/backup.c @@ -317,11 +317,12 @@ typedef struct { int ret; } BackupCompleteData; =20 -static void backup_complete(BlockJob *job, void *opaque) +static void backup_complete(Job *job, void *opaque) { + BlockJob *bjob =3D container_of(job, BlockJob, job); BackupCompleteData *data =3D opaque; =20 - block_job_completed(job, data->ret); + block_job_completed(bjob, data->ret); g_free(data); } =20 @@ -519,7 +520,7 @@ static void coroutine_fn backup_run(void *opaque) =20 data =3D g_malloc(sizeof(*data)); data->ret =3D ret; - block_job_defer_to_main_loop(&job->common, backup_complete, data); + job_defer_to_main_loop(&job->common.job, backup_complete, data); } =20 static const BlockJobDriver backup_job_driver =3D { diff --git a/block/commit.c b/block/commit.c index 85baea8f92..d326766e4d 100644 --- a/block/commit.c +++ b/block/commit.c @@ -72,9 +72,10 @@ typedef struct { int ret; } CommitCompleteData; =20 -static void commit_complete(BlockJob *job, void *opaque) +static void commit_complete(Job *job, void *opaque) { - CommitBlockJob *s =3D container_of(job, CommitBlockJob, common); + CommitBlockJob *s =3D container_of(job, CommitBlockJob, common.job); + BlockJob *bjob =3D &s->common; CommitCompleteData *data =3D opaque; BlockDriverState *top =3D blk_bs(s->top); BlockDriverState *base =3D blk_bs(s->base); @@ -90,7 +91,7 @@ static void commit_complete(BlockJob *job, void *opaque) * the normal backing chain can be restored. */ blk_unref(s->base); =20 - if (!job_is_cancelled(&s->common.job) && ret =3D=3D 0) { + if (!job_is_cancelled(job) && ret =3D=3D 0) { /* success */ ret =3D bdrv_drop_intermediate(s->commit_top_bs, base, s->backing_file_str); @@ -114,7 +115,7 @@ static void commit_complete(BlockJob *job, void *opaque) * block_job_finish_sync()), block_job_completed() won't free it and * therefore the blockers on the intermediate nodes remain. This would * cause bdrv_set_backing_hd() to fail. */ - block_job_remove_all_bdrv(job); + block_job_remove_all_bdrv(bjob); =20 block_job_completed(&s->common, ret); g_free(data); @@ -211,7 +212,7 @@ out: =20 data =3D g_malloc(sizeof(*data)); data->ret =3D ret; - block_job_defer_to_main_loop(&s->common, commit_complete, data); + job_defer_to_main_loop(&s->common.job, commit_complete, data); } =20 static const BlockJobDriver commit_job_driver =3D { diff --git a/block/mirror.c b/block/mirror.c index 937b915268..cb6a4f6fe1 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -484,9 +484,10 @@ typedef struct { int ret; } MirrorExitData; =20 -static void mirror_exit(BlockJob *job, void *opaque) +static void mirror_exit(Job *job, void *opaque) { - MirrorBlockJob *s =3D container_of(job, MirrorBlockJob, common); + MirrorBlockJob *s =3D container_of(job, MirrorBlockJob, common.job); + BlockJob *bjob =3D &s->common; MirrorExitData *data =3D opaque; AioContext *replace_aio_context =3D NULL; BlockDriverState *src =3D s->source; @@ -568,7 +569,7 @@ static void mirror_exit(BlockJob *job, void *opaque) * the blockers on the intermediate nodes so that the resulting state = is * valid. Also give up permissions on mirror_top_bs->backing, which mi= ght * block the removal. */ - block_job_remove_all_bdrv(job); + block_job_remove_all_bdrv(bjob); bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL, &error_abort); bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abo= rt); @@ -576,9 +577,9 @@ static void mirror_exit(BlockJob *job, void *opaque) /* We just changed the BDS the job BB refers to (with either or both o= f the * bdrv_replace_node() calls), so switch the BB back so the cleanup do= es * the right thing. We don't need any permissions any more now. */ - blk_remove_bs(job->blk); - blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort); - blk_insert_bs(job->blk, mirror_top_bs, &error_abort); + blk_remove_bs(bjob->blk); + blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); + blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort); =20 block_job_completed(&s->common, data->ret); =20 @@ -897,7 +898,7 @@ immediate_exit: if (need_drain) { bdrv_drained_begin(bs); } - block_job_defer_to_main_loop(&s->common, mirror_exit, data); + job_defer_to_main_loop(&s->common.job, mirror_exit, data); } =20 static void mirror_complete(BlockJob *job, Error **errp) diff --git a/block/stream.c b/block/stream.c index 22c71ae100..0bba81678c 100644 --- a/block/stream.c +++ b/block/stream.c @@ -58,16 +58,16 @@ typedef struct { int ret; } StreamCompleteData; =20 -static void stream_complete(BlockJob *job, void *opaque) +static void stream_complete(Job *job, void *opaque) { - StreamBlockJob *s =3D container_of(job, StreamBlockJob, common); + StreamBlockJob *s =3D container_of(job, StreamBlockJob, common.job); + BlockJob *bjob =3D &s->common; StreamCompleteData *data =3D opaque; - BlockDriverState *bs =3D blk_bs(job->blk); + BlockDriverState *bs =3D blk_bs(bjob->blk); BlockDriverState *base =3D s->base; Error *local_err =3D NULL; =20 - if (!job_is_cancelled(&s->common.job) && bs->backing && - data->ret =3D=3D 0) { + if (!job_is_cancelled(job) && bs->backing && data->ret =3D=3D 0) { const char *base_id =3D NULL, *base_fmt =3D NULL; if (base) { base_id =3D s->backing_file_str; @@ -88,7 +88,7 @@ out: /* Reopen the image back in read-only mode if necessary */ if (s->bs_flags !=3D bdrv_get_flags(bs)) { /* Give up write permissions before making it read-only */ - blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort); + blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); bdrv_reopen(bs, s->bs_flags, NULL); } =20 @@ -205,7 +205,7 @@ out: /* Modify backing chain and close BDSes in main loop */ data =3D g_malloc(sizeof(*data)); data->ret =3D ret; - block_job_defer_to_main_loop(&s->common, stream_complete, data); + job_defer_to_main_loop(&s->common.job, stream_complete, data); } =20 static const BlockJobDriver stream_job_driver =3D { diff --git a/blockjob.c b/blockjob.c index 734dd168dd..7524058e45 100644 --- a/blockjob.c +++ b/blockjob.c @@ -347,7 +347,7 @@ static void block_job_decommission(BlockJob *job) job->completed =3D true; job->busy =3D false; job->paused =3D false; - job->deferred_to_main_loop =3D true; + job->job.deferred_to_main_loop =3D true; block_job_txn_del_job(job); job_state_transition(&job->job, JOB_STATUS_NULL); job_unref(&job->job); @@ -502,7 +502,7 @@ static int block_job_finish_sync(BlockJob *job, /* block_job_drain calls block_job_enter, and it should be enough to * induce progress until the job completes or moves to the main thread. */ - while (!job->deferred_to_main_loop && !job->completed) { + while (!job->job.deferred_to_main_loop && !job->completed) { block_job_drain(job); } while (!job->completed) { @@ -722,7 +722,7 @@ void block_job_cancel(BlockJob *job, bool force) block_job_cancel_async(job, force); if (!block_job_started(job)) { block_job_completed(job, -ECANCELED); - } else if (job->deferred_to_main_loop) { + } else if (job->job.deferred_to_main_loop) { block_job_completed_txn_abort(job); } else { block_job_enter(job); @@ -1036,7 +1036,7 @@ static void block_job_enter_cond(BlockJob *job, bool(= *fn)(BlockJob *job)) if (!block_job_started(job)) { return; } - if (job->deferred_to_main_loop) { + if (job->job.deferred_to_main_loop) { return; } =20 @@ -1051,7 +1051,7 @@ static void block_job_enter_cond(BlockJob *job, bool(= *fn)(BlockJob *job)) return; } =20 - assert(!job->deferred_to_main_loop); + assert(!job->job.deferred_to_main_loop); timer_del(&job->sleep_timer); job->busy =3D true; block_job_unlock(); @@ -1157,50 +1157,3 @@ BlockErrorAction block_job_error_action(BlockJob *jo= b, BlockdevOnError on_err, } return action; } - -typedef struct { - BlockJob *job; - AioContext *aio_context; - BlockJobDeferToMainLoopFn *fn; - void *opaque; -} BlockJobDeferToMainLoopData; - -static void block_job_defer_to_main_loop_bh(void *opaque) -{ - BlockJobDeferToMainLoopData *data =3D opaque; - AioContext *aio_context; - - /* Prevent race with block_job_defer_to_main_loop() */ - aio_context_acquire(data->aio_context); - - /* Fetch BDS AioContext again, in case it has changed */ - aio_context =3D blk_get_aio_context(data->job->blk); - if (aio_context !=3D data->aio_context) { - aio_context_acquire(aio_context); - } - - data->fn(data->job, data->opaque); - - if (aio_context !=3D data->aio_context) { - aio_context_release(aio_context); - } - - aio_context_release(data->aio_context); - - g_free(data); -} - -void block_job_defer_to_main_loop(BlockJob *job, - BlockJobDeferToMainLoopFn *fn, - void *opaque) -{ - BlockJobDeferToMainLoopData *data =3D g_malloc(sizeof(*data)); - data->job =3D job; - data->aio_context =3D blk_get_aio_context(job->blk); - data->fn =3D fn; - data->opaque =3D opaque; - job->deferred_to_main_loop =3D true; - - aio_bh_schedule_oneshot(qemu_get_aio_context(), - block_job_defer_to_main_loop_bh, data); -} diff --git a/job.c b/job.c index a28a7765e5..8e79bcfb74 100644 --- a/job.c +++ b/job.c @@ -28,6 +28,7 @@ #include "qapi/error.h" #include "qemu/job.h" #include "qemu/id.h" +#include "qemu/main-loop.h" #include "trace-root.h" =20 static QLIST_HEAD(, Job) jobs =3D QLIST_HEAD_INITIALIZER(jobs); @@ -171,3 +172,35 @@ void job_unref(Job *job) g_free(job); } } + +typedef struct { + Job *job; + JobDeferToMainLoopFn *fn; + void *opaque; +} JobDeferToMainLoopData; + +static void job_defer_to_main_loop_bh(void *opaque) +{ + JobDeferToMainLoopData *data =3D opaque; + Job *job =3D data->job; + AioContext *aio_context =3D job->aio_context; + + /* Prevent race with job_defer_to_main_loop() */ + aio_context_acquire(aio_context); + data->fn(data->job, data->opaque); + aio_context_release(aio_context); + + g_free(data); +} + +void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaq= ue) +{ + JobDeferToMainLoopData *data =3D g_malloc(sizeof(*data)); + data->job =3D job; + data->fn =3D fn; + data->opaque =3D opaque; + job->deferred_to_main_loop =3D true; + + aio_bh_schedule_oneshot(qemu_get_aio_context(), + job_defer_to_main_loop_bh, data); +} diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index f9e37d479c..4f8cba8377 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -496,9 +496,10 @@ typedef struct TestBlockJob { bool should_complete; } TestBlockJob; =20 -static void test_job_completed(BlockJob *job, void *opaque) +static void test_job_completed(Job *job, void *opaque) { - block_job_completed(job, 0); + BlockJob *bjob =3D container_of(job, BlockJob, job); + block_job_completed(bjob, 0); } =20 static void coroutine_fn test_job_start(void *opaque) @@ -510,7 +511,7 @@ static void coroutine_fn test_job_start(void *opaque) block_job_sleep_ns(&s->common, 100000); } =20 - block_job_defer_to_main_loop(&s->common, test_job_completed, NULL); + job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); } =20 static void test_job_complete(BlockJob *job, Error **errp) diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 26b4bbb230..c03f9662d8 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -24,16 +24,17 @@ typedef struct { int *result; } TestBlockJob; =20 -static void test_block_job_complete(BlockJob *job, void *opaque) +static void test_block_job_complete(Job *job, void *opaque) { - BlockDriverState *bs =3D blk_bs(job->blk); + BlockJob *bjob =3D container_of(job, BlockJob, job); + BlockDriverState *bs =3D blk_bs(bjob->blk); int rc =3D (intptr_t)opaque; =20 - if (job_is_cancelled(&job->job)) { + if (job_is_cancelled(job)) { rc =3D -ECANCELED; } =20 - block_job_completed(job, rc); + block_job_completed(bjob, rc); bdrv_unref(bs); } =20 @@ -54,8 +55,8 @@ static void coroutine_fn test_block_job_run(void *opaque) } } =20 - block_job_defer_to_main_loop(job, test_block_job_complete, - (void *)(intptr_t)s->rc); + job_defer_to_main_loop(&job->job, test_block_job_complete, + (void *)(intptr_t)s->rc); } =20 typedef struct { diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index fa31481537..5f43bd72a4 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -161,11 +161,12 @@ typedef struct CancelJob { bool completed; } CancelJob; =20 -static void cancel_job_completed(BlockJob *job, void *opaque) +static void cancel_job_completed(Job *job, void *opaque) { + BlockJob *bjob =3D container_of(job, BlockJob, job); CancelJob *s =3D opaque; s->completed =3D true; - block_job_completed(job, 0); + block_job_completed(bjob, 0); } =20 static void cancel_job_complete(BlockJob *job, Error **errp) @@ -191,7 +192,7 @@ static void coroutine_fn cancel_job_start(void *opaque) } =20 defer: - block_job_defer_to_main_loop(&s->common, cancel_job_completed, s); + job_defer_to_main_loop(&s->common.job, cancel_job_completed, s); } =20 static const BlockJobDriver test_cancel_driver =3D { --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585796997236.95501379242512; Tue, 24 Apr 2018 09:03:16 -0700 (PDT) Received: from localhost ([::1]:59320 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0PS-0004K8-Qa for importer@patchew.org; Tue, 24 Apr 2018 12:03:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48162) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpU-0008LL-QC for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpQ-0008Rw-MN for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:04 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34848 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpB-00088N-Mr; Tue, 24 Apr 2018 11:25:45 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 48970738E0; Tue, 24 Apr 2018 15:25:45 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 19C8C202342F; Tue, 24 Apr 2018 15:25:43 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:24:59 +0200 Message-Id: <20180424152515.25664-18-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:45 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:45 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 17/33] job: Move coroutine and related code to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This commit moves some core functions for dealing with the job coroutine from BlockJob to Job. This includes primarily entering the coroutine (both for the first and reentering) and yielding explicitly and at pause points. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 40 --------- include/block/blockjob_int.h | 26 ------ include/qemu/job.h | 70 +++++++++++++++ block/backup.c | 2 +- block/commit.c | 4 +- block/mirror.c | 22 ++--- block/replication.c | 2 +- block/stream.c | 4 +- blockdev.c | 8 +- blockjob.c | 201 +++++++--------------------------------= ---- job.c | 141 ++++++++++++++++++++++++++++++ tests/test-bdrv-drain.c | 38 ++++---- tests/test-blockjob-txn.c | 12 +-- tests/test-blockjob.c | 14 +-- 14 files changed, 294 insertions(+), 290 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 90942826f5..c0448206e2 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -51,43 +51,18 @@ typedef struct BlockJob { BlockBackend *blk; =20 /** - * The coroutine that executes the job. If not NULL, it is - * reentered when busy is false and the job is cancelled. - */ - Coroutine *co; - - /** * Set to true if the job should abort immediately without waiting * for data to be in sync. */ bool force; =20 /** - * Counter for pause request. If non-zero, the block job is either pau= sed, - * or if busy =3D=3D true will pause itself as soon as possible. - */ - int pause_count; - - /** * Set to true if the job is paused by user. Can be unpaused with the * block-job-resume QMP command. */ bool user_paused; =20 /** - * Set to false by the job while the coroutine has yielded and may be - * re-entered by block_job_enter(). There may still be I/O or event l= oop - * activity pending. Accessed under block_job_mutex (in blockjob.c). - */ - bool busy; - - /** - * Set to true by the job while it is in a quiescent state, where - * no I/O or event loop activity is pending. - */ - bool paused; - - /** * Set to true when the job is ready to be completed. */ bool ready; @@ -125,12 +100,6 @@ typedef struct BlockJob { /** ret code passed to block_job_completed. */ int ret; =20 - /** - * Timer that is used by @block_job_sleep_ns. Accessed under - * block_job_mutex (in blockjob.c). - */ - QEMUTimer sleep_timer; - /** True if this job should automatically finalize itself */ bool auto_finalize; =20 @@ -208,15 +177,6 @@ void block_job_remove_all_bdrv(BlockJob *job); void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); =20 /** - * block_job_start: - * @job: A job that has not yet been started. - * - * Begins execution of a block job. - * Takes ownership of one reference to the job object. - */ -void block_job_start(BlockJob *job); - -/** * block_job_cancel: * @job: The job to be canceled. * @force: Quit a job without waiting for data to be in sync. diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index b0338282c8..8bf7fbc94a 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -38,9 +38,6 @@ struct BlockJobDriver { /** Generic JobDriver callbacks and settings */ JobDriver job_driver; =20 - /** Mandatory: Entrypoint for the Coroutine. */ - CoroutineEntry *start; - /** * Optional callback for job types whose completion must be triggered * manually. @@ -85,20 +82,6 @@ struct BlockJobDriver { */ void (*clean)(BlockJob *job); =20 - /** - * If the callback is not NULL, it will be invoked when the job transi= tions - * into the paused state. Paused jobs must not perform any asynchrono= us - * I/O or event loop activity. This callback is used to quiesce jobs. - */ - void coroutine_fn (*pause)(BlockJob *job); - - /** - * If the callback is not NULL, it will be invoked when the job transi= tions - * out of the paused state. Any asynchronous I/O or event loop activi= ty - * should be restarted from this callback. - */ - void coroutine_fn (*resume)(BlockJob *job); - /* * If the callback is not NULL, it will be invoked before the job is * resumed in a new AioContext. This is the place to move any resourc= es @@ -196,15 +179,6 @@ void block_job_early_fail(BlockJob *job); void block_job_completed(BlockJob *job, int ret); =20 /** - * block_job_pause_point: - * @job: The job that is ready to pause. - * - * Pause now if block_job_pause() has been called. Block jobs that perform - * lots of I/O must call this between requests so that the job can be paus= ed. - */ -void coroutine_fn block_job_pause_point(BlockJob *job); - -/** * block_job_enter: * @job: The job to enter. * diff --git a/include/qemu/job.h b/include/qemu/job.h index 63a40b2714..8e636ba970 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -28,6 +28,7 @@ =20 #include "qapi/qapi-types-block-core.h" #include "qemu/queue.h" +#include "qemu/coroutine.h" =20 typedef struct JobDriver JobDriver; =20 @@ -51,6 +52,37 @@ typedef struct Job { AioContext *aio_context; =20 /** + * The coroutine that executes the job. If not NULL, it is reentered = when + * busy is false and the job is cancelled. + */ + Coroutine *co; + + /** + * Timer that is used by @block_job_sleep_ns. Accessed under job_mutex= (in + * job.c). + */ + QEMUTimer sleep_timer; + + /** + * Counter for pause request. If non-zero, the block job is either pau= sed, + * or if busy =3D=3D true will pause itself as soon as possible. + */ + int pause_count; + + /** + * Set to false by the job while the coroutine has yielded and may be + * re-entered by block_job_enter(). There may still be I/O or event l= oop + * activity pending. Accessed under block_job_mutex (in blockjob.c). + */ + bool busy; + + /** + * Set to true by the job while it is in a quiescent state, where + * no I/O or event loop activity is pending. + */ + bool paused; + + /** * Set to true if the job should cancel itself. The flag must * always be tested just before toggling the busy flag from false * to true. After a job has been cancelled, it should only yield @@ -75,6 +107,23 @@ struct JobDriver { /** Enum describing the operation */ JobType job_type; =20 + /** Mandatory: Entrypoint for the Coroutine. */ + CoroutineEntry *start; + + /** + * If the callback is not NULL, it will be invoked when the job transi= tions + * into the paused state. Paused jobs must not perform any asynchrono= us + * I/O or event loop activity. This callback is used to quiesce jobs. + */ + void coroutine_fn (*pause)(Job *job); + + /** + * If the callback is not NULL, it will be invoked when the job transi= tions + * out of the paused state. Any asynchronous I/O or event loop activi= ty + * should be restarted from this callback. + */ + void coroutine_fn (*resume)(Job *job); + /** Called when the job is freed */ void (*free)(Job *job); }; @@ -103,6 +152,23 @@ void job_ref(Job *job); */ void job_unref(Job *job); =20 +/** + * @job: A job that has not yet been started. + * + * Begins execution of a job. + * Takes ownership of one reference to the job object. + */ +void job_start(Job *job); + +/** + * @job: The job that is ready to pause. + * + * Pause now if job_pause() has been called. Jobs that perform lots of I/O + * must call this between requests so that the job can be paused. + */ +void coroutine_fn job_pause_point(Job *job); + + /** Returns the JobType of a given Job. */ JobType job_type(Job *job); =20 @@ -147,5 +213,9 @@ void job_defer_to_main_loop(Job *job, JobDeferToMainLoo= pFn *fn, void *opaque); /* TODO To be removed from the public interface */ void job_state_transition(Job *job, JobStatus s1); int job_apply_verb(Job *job, JobVerb bv, Error **errp); +void coroutine_fn job_do_yield(Job *job, uint64_t ns); +bool job_should_pause(Job *job); +bool job_started(Job *job); +void job_enter_cond(Job *job, bool(*fn)(Job *job)); =20 #endif diff --git a/block/backup.c b/block/backup.c index ce9cc01617..f81c137050 100644 --- a/block/backup.c +++ b/block/backup.c @@ -528,8 +528,8 @@ static const BlockJobDriver backup_job_driver =3D { .instance_size =3D sizeof(BackupBlockJob), .job_type =3D JOB_TYPE_BACKUP, .free =3D block_job_free, + .start =3D backup_run, }, - .start =3D backup_run, .commit =3D backup_commit, .abort =3D backup_abort, .clean =3D backup_clean, diff --git a/block/commit.c b/block/commit.c index d326766e4d..2fbc31077a 100644 --- a/block/commit.c +++ b/block/commit.c @@ -220,8 +220,8 @@ static const BlockJobDriver commit_job_driver =3D { .instance_size =3D sizeof(CommitBlockJob), .job_type =3D JOB_TYPE_COMMIT, .free =3D block_job_free, + .start =3D commit_run, }, - .start =3D commit_run, }; =20 static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs, @@ -371,7 +371,7 @@ void commit_start(const char *job_id, BlockDriverState = *bs, s->on_error =3D on_error; =20 trace_commit_start(bs, base, top, s); - block_job_start(&s->common); + job_start(&s->common.job); return; =20 fail: diff --git a/block/mirror.c b/block/mirror.c index cb6a4f6fe1..36f21f6e7d 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -126,7 +126,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret) g_free(op); =20 if (s->waiting_for_io) { - qemu_coroutine_enter(s->common.co); + qemu_coroutine_enter(s->common.job.co); } } =20 @@ -345,7 +345,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlo= ckJob *s) mirror_wait_for_io(s); } =20 - block_job_pause_point(&s->common); + job_pause_point(&s->common.job); =20 /* Find the number of consective dirty chunks following the first dirty * one, and wait for in flight requests in them. */ @@ -597,7 +597,7 @@ static void mirror_throttle(MirrorBlockJob *s) s->last_pause_ns =3D now; block_job_sleep_ns(&s->common, 0); } else { - block_job_pause_point(&s->common); + job_pause_point(&s->common.job); } } =20 @@ -786,7 +786,7 @@ static void coroutine_fn mirror_run(void *opaque) goto immediate_exit; } =20 - block_job_pause_point(&s->common); + job_pause_point(&s->common.job); =20 cnt =3D bdrv_get_dirty_count(s->dirty_bitmap); /* cnt is the number of dirty bytes remaining and s->bytes_in_flig= ht is @@ -953,9 +953,9 @@ static void mirror_complete(BlockJob *job, Error **errp) block_job_enter(&s->common); } =20 -static void mirror_pause(BlockJob *job) +static void mirror_pause(Job *job) { - MirrorBlockJob *s =3D container_of(job, MirrorBlockJob, common); + MirrorBlockJob *s =3D container_of(job, MirrorBlockJob, common.job); =20 mirror_wait_for_all_io(s); } @@ -987,10 +987,10 @@ static const BlockJobDriver mirror_job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), .job_type =3D JOB_TYPE_MIRROR, .free =3D block_job_free, + .start =3D mirror_run, + .pause =3D mirror_pause, }, - .start =3D mirror_run, .complete =3D mirror_complete, - .pause =3D mirror_pause, .attached_aio_context =3D mirror_attached_aio_context, .drain =3D mirror_drain, }; @@ -1000,10 +1000,10 @@ static const BlockJobDriver commit_active_job_drive= r =3D { .instance_size =3D sizeof(MirrorBlockJob), .job_type =3D JOB_TYPE_COMMIT, .free =3D block_job_free, + .start =3D mirror_run, + .pause =3D mirror_pause, }, - .start =3D mirror_run, .complete =3D mirror_complete, - .pause =3D mirror_pause, .attached_aio_context =3D mirror_attached_aio_context, .drain =3D mirror_drain, }; @@ -1238,7 +1238,7 @@ static void mirror_start_job(const char *job_id, Bloc= kDriverState *bs, } =20 trace_mirror_start(bs, s, opaque); - block_job_start(&s->common); + job_start(&s->common.job); return; =20 fail: diff --git a/block/replication.c b/block/replication.c index 6c0c7186d9..3f7500ee3f 100644 --- a/block/replication.c +++ b/block/replication.c @@ -574,7 +574,7 @@ static void replication_start(ReplicationState *rs, Rep= licationMode mode, aio_context_release(aio_context); return; } - block_job_start(job); + job_start(&job->job); break; default: aio_context_release(aio_context); diff --git a/block/stream.c b/block/stream.c index 0bba81678c..6d8b7b6eee 100644 --- a/block/stream.c +++ b/block/stream.c @@ -213,8 +213,8 @@ static const BlockJobDriver stream_job_driver =3D { .instance_size =3D sizeof(StreamBlockJob), .job_type =3D JOB_TYPE_STREAM, .free =3D block_job_free, + .start =3D stream_run, }, - .start =3D stream_run, }; =20 void stream_start(const char *job_id, BlockDriverState *bs, @@ -262,7 +262,7 @@ void stream_start(const char *job_id, BlockDriverState = *bs, =20 s->on_error =3D on_error; trace_stream_start(bs, base, s); - block_job_start(&s->common); + job_start(&s->common.job); return; =20 fail: diff --git a/blockdev.c b/blockdev.c index c31bf3d98d..44471b28d7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1910,7 +1910,7 @@ static void drive_backup_commit(BlkActionState *commo= n) aio_context_acquire(aio_context); =20 assert(state->job); - block_job_start(state->job); + job_start(&state->job->job); =20 aio_context_release(aio_context); } @@ -2008,7 +2008,7 @@ static void blockdev_backup_commit(BlkActionState *co= mmon) aio_context_acquire(aio_context); =20 assert(state->job); - block_job_start(state->job); + job_start(&state->job->job); =20 aio_context_release(aio_context); } @@ -3425,7 +3425,7 @@ void qmp_drive_backup(DriveBackup *arg, Error **errp) BlockJob *job; job =3D do_drive_backup(arg, NULL, errp); if (job) { - block_job_start(job); + job_start(&job->job); } } =20 @@ -3513,7 +3513,7 @@ void qmp_blockdev_backup(BlockdevBackup *arg, Error *= *errp) BlockJob *job; job =3D do_blockdev_backup(arg, NULL, errp); if (job) { - block_job_start(job); + job_start(&job->job); } } =20 diff --git a/blockjob.c b/blockjob.c index 7524058e45..ca4d50aaef 100644 --- a/blockjob.c +++ b/blockjob.c @@ -36,30 +36,9 @@ #include "qemu/coroutine.h" #include "qemu/timer.h" =20 -/* Right now, this mutex is only needed to synchronize accesses to job->bu= sy - * and job->sleep_timer, such as concurrent calls to block_job_do_yield and - * block_job_enter. */ -static QemuMutex block_job_mutex; - -static void block_job_lock(void) -{ - qemu_mutex_lock(&block_job_mutex); -} - -static void block_job_unlock(void) -{ - qemu_mutex_unlock(&block_job_mutex); -} - -static void __attribute__((__constructor__)) block_job_init(void) -{ - qemu_mutex_init(&block_job_mutex); -} - static void block_job_event_cancelled(BlockJob *job); static void block_job_event_completed(BlockJob *job, const char *msg); static int block_job_event_pending(BlockJob *job); -static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)); =20 /* Transactional group of block jobs */ struct BlockJobTxn { @@ -164,14 +143,14 @@ static void block_job_txn_del_job(BlockJob *job) =20 static void block_job_pause(BlockJob *job) { - job->pause_count++; + job->job.pause_count++; } =20 static void block_job_resume(BlockJob *job) { - assert(job->pause_count > 0); - job->pause_count--; - if (job->pause_count) { + assert(job->job.pause_count > 0); + job->job.pause_count--; + if (job->job.pause_count) { return; } block_job_enter(job); @@ -195,7 +174,7 @@ void block_job_free(Job *job) block_job_detach_aio_context, bjob); blk_unref(bjob->blk); error_free(bjob->blocker); - assert(!timer_pending(&bjob->sleep_timer)); + assert(!timer_pending(&bjob->job.sleep_timer)); } =20 static void block_job_attached_aio_context(AioContext *new_context, @@ -213,7 +192,7 @@ static void block_job_attached_aio_context(AioContext *= new_context, =20 static void block_job_drain(BlockJob *job) { - /* If job is !job->busy this kicks it into the next pause point. */ + /* If job is !job->job.busy this kicks it into the next pause point. */ block_job_enter(job); =20 blk_drain(job->blk); @@ -231,7 +210,7 @@ static void block_job_detach_aio_context(void *opaque) =20 block_job_pause(job); =20 - while (!job->paused && !job->completed) { + while (!job->job.paused && !job->completed) { block_job_drain(job); } =20 @@ -299,29 +278,11 @@ bool block_job_is_internal(BlockJob *job) return (job->job.id =3D=3D NULL); } =20 -static bool block_job_started(BlockJob *job) -{ - return job->co; -} - const BlockJobDriver *block_job_driver(BlockJob *job) { return job->driver; } =20 -/** - * All jobs must allow a pause point before entering their job proper. This - * ensures that jobs can be paused prior to being started, then resumed la= ter. - */ -static void coroutine_fn block_job_co_entry(void *opaque) -{ - BlockJob *job =3D opaque; - - assert(job && job->driver && job->driver->start); - block_job_pause_point(job); - job->driver->start(job); -} - static void block_job_sleep_timer_cb(void *opaque) { BlockJob *job =3D opaque; @@ -329,24 +290,12 @@ static void block_job_sleep_timer_cb(void *opaque) block_job_enter(job); } =20 -void block_job_start(BlockJob *job) -{ - assert(job && !block_job_started(job) && job->paused && - job->driver && job->driver->start); - job->co =3D qemu_coroutine_create(block_job_co_entry, job); - job->pause_count--; - job->busy =3D true; - job->paused =3D false; - job_state_transition(&job->job, JOB_STATUS_RUNNING); - bdrv_coroutine_enter(blk_bs(job->blk), job->co); -} - static void block_job_decommission(BlockJob *job) { assert(job); job->completed =3D true; - job->busy =3D false; - job->paused =3D false; + job->job.busy =3D false; + job->job.paused =3D false; job->job.deferred_to_main_loop =3D true; block_job_txn_del_job(job); job_state_transition(&job->job, JOB_STATUS_NULL); @@ -361,7 +310,7 @@ static void block_job_do_dismiss(BlockJob *job) static void block_job_conclude(BlockJob *job) { job_state_transition(&job->job, JOB_STATUS_CONCLUDED); - if (job->auto_dismiss || !block_job_started(job)) { + if (job->auto_dismiss || !job_started(&job->job)) { block_job_do_dismiss(job); } } @@ -426,7 +375,7 @@ static int block_job_finalize_single(BlockJob *job) } =20 /* Emit events only if we actually started */ - if (block_job_started(job)) { + if (job_started(&job->job)) { if (job_is_cancelled(&job->job)) { block_job_event_cancelled(job); } else { @@ -451,7 +400,7 @@ static void block_job_cancel_async(BlockJob *job, bool = force) if (job->user_paused) { /* Do not call block_job_enter here, the caller will handle it. */ job->user_paused =3D false; - job->pause_count--; + job->job.pause_count--; } job->job.cancelled =3D true; /* To prevent 'force =3D=3D false' overriding a previous 'force =3D=3D= true' */ @@ -603,7 +552,7 @@ static void block_job_completed_txn_success(BlockJob *j= ob) } =20 /* Assumes the block_job_mutex is held */ -static bool block_job_timer_pending(BlockJob *job) +static bool job_timer_pending(Job *job) { return timer_pending(&job->sleep_timer); } @@ -628,7 +577,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, = Error **errp) } =20 /* kick only if a timer is pending */ - block_job_enter_cond(job, block_job_timer_pending); + job_enter_cond(&job->job, job_timer_pending); } =20 int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) @@ -647,7 +596,7 @@ void block_job_complete(BlockJob *job, Error **errp) if (job_apply_verb(&job->job, JOB_VERB_COMPLETE, errp)) { return; } - if (job->pause_count || job_is_cancelled(&job->job) || + if (job->job.pause_count || job_is_cancelled(&job->job) || !job->driver->complete) { error_setg(errp, "The active block job '%s' cannot be completed", @@ -701,7 +650,7 @@ bool block_job_user_paused(BlockJob *job) void block_job_user_resume(BlockJob *job, Error **errp) { assert(job); - if (!job->user_paused || job->pause_count <=3D 0) { + if (!job->user_paused || job->job.pause_count <=3D 0) { error_setg(errp, "Can't resume a job that was not paused"); return; } @@ -720,7 +669,7 @@ void block_job_cancel(BlockJob *job, bool force) return; } block_job_cancel_async(job, force); - if (!block_job_started(job)) { + if (!job_started(&job->job)) { block_job_completed(job, -ECANCELED); } else if (job->job.deferred_to_main_loop) { block_job_completed_txn_abort(job); @@ -790,8 +739,8 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **er= rp) info->type =3D g_strdup(job_type_str(&job->job)); info->device =3D g_strdup(job->job.id); info->len =3D job->len; - info->busy =3D atomic_read(&job->busy); - info->paused =3D job->pause_count > 0; + info->busy =3D atomic_read(&job->job.busy); + info->paused =3D job->job.pause_count > 0; info->offset =3D job->offset; info->speed =3D job->speed; info->io_status =3D job->iostatus; @@ -906,12 +855,9 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, job->blk =3D blk; job->cb =3D cb; job->opaque =3D opaque; - job->busy =3D false; - job->paused =3D true; - job->pause_count =3D 1; job->auto_finalize =3D !(flags & BLOCK_JOB_MANUAL_FINALIZE); job->auto_dismiss =3D !(flags & BLOCK_JOB_MANUAL_DISMISS); - aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, + aio_timer_init(qemu_get_aio_context(), &job->job.sleep_timer, QEMU_CLOCK_REALTIME, SCALE_NS, block_job_sleep_timer_cb, job); =20 @@ -971,128 +917,41 @@ void block_job_completed(BlockJob *job, int ret) } } =20 -static bool block_job_should_pause(BlockJob *job) -{ - return job->pause_count > 0; -} - -/* Yield, and schedule a timer to reenter the coroutine after @ns nanoseco= nds. - * Reentering the job coroutine with block_job_enter() before the timer has - * expired is allowed and cancels the timer. - * - * If @ns is (uint64_t) -1, no timer is scheduled and block_job_enter() mu= st be - * called explicitly. */ -static void block_job_do_yield(BlockJob *job, uint64_t ns) -{ - block_job_lock(); - if (ns !=3D -1) { - timer_mod(&job->sleep_timer, ns); - } - job->busy =3D false; - block_job_unlock(); - qemu_coroutine_yield(); - - /* Set by block_job_enter before re-entering the coroutine. */ - assert(job->busy); -} - -void coroutine_fn block_job_pause_point(BlockJob *job) -{ - assert(job && block_job_started(job)); - - if (!block_job_should_pause(job)) { - return; - } - if (job_is_cancelled(&job->job)) { - return; - } - - if (job->driver->pause) { - job->driver->pause(job); - } - - if (block_job_should_pause(job) && !job_is_cancelled(&job->job)) { - JobStatus status =3D job->job.status; - job_state_transition(&job->job, status =3D=3D JOB_STATUS_READY - ? JOB_STATUS_STANDBY - : JOB_STATUS_PAUSED); - job->paused =3D true; - block_job_do_yield(job, -1); - job->paused =3D false; - job_state_transition(&job->job, status); - } - - if (job->driver->resume) { - job->driver->resume(job); - } -} - -/* - * Conditionally enter a block_job pending a call to fn() while - * under the block_job_lock critical section. - */ -static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)) -{ - if (!block_job_started(job)) { - return; - } - if (job->job.deferred_to_main_loop) { - return; - } - - block_job_lock(); - if (job->busy) { - block_job_unlock(); - return; - } - - if (fn && !fn(job)) { - block_job_unlock(); - return; - } - - assert(!job->job.deferred_to_main_loop); - timer_del(&job->sleep_timer); - job->busy =3D true; - block_job_unlock(); - aio_co_wake(job->co); -} - void block_job_enter(BlockJob *job) { - block_job_enter_cond(job, NULL); + job_enter_cond(&job->job, NULL); } =20 void block_job_sleep_ns(BlockJob *job, int64_t ns) { - assert(job->busy); + assert(job->job.busy); =20 /* Check cancellation *before* setting busy =3D false, too! */ if (job_is_cancelled(&job->job)) { return; } =20 - if (!block_job_should_pause(job)) { - block_job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + n= s); + if (!job_should_pause(&job->job)) { + job_do_yield(&job->job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + n= s); } =20 - block_job_pause_point(job); + job_pause_point(&job->job); } =20 void block_job_yield(BlockJob *job) { - assert(job->busy); + assert(job->job.busy); =20 /* Check cancellation *before* setting busy =3D false, too! */ if (job_is_cancelled(&job->job)) { return; } =20 - if (!block_job_should_pause(job)) { - block_job_do_yield(job, -1); + if (!job_should_pause(&job->job)) { + job_do_yield(&job->job, -1); } =20 - block_job_pause_point(job); + job_pause_point(&job->job); } =20 void block_job_iostatus_reset(BlockJob *job) @@ -1100,7 +959,7 @@ void block_job_iostatus_reset(BlockJob *job) if (job->iostatus =3D=3D BLOCK_DEVICE_IO_STATUS_OK) { return; } - assert(job->user_paused && job->pause_count > 0); + assert(job->user_paused && job->job.pause_count > 0); job->iostatus =3D BLOCK_DEVICE_IO_STATUS_OK; } =20 diff --git a/job.c b/job.c index 8e79bcfb74..ea4ee8a325 100644 --- a/job.c +++ b/job.c @@ -60,6 +60,26 @@ bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] =3D { [JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, }; =20 +/* Right now, this mutex is only needed to synchronize accesses to job->bu= sy + * and job->sleep_timer, such as concurrent calls to job_do_yield and + * job_enter. */ +static QemuMutex job_mutex; + +static void job_lock(void) +{ + qemu_mutex_lock(&job_mutex); +} + +static void job_unlock(void) +{ + qemu_mutex_unlock(&job_mutex); +} + +static void __attribute__((__constructor__)) job_init(void) +{ + qemu_mutex_init(&job_mutex); +} + /* TODO Make static once the whole state machine is in job.c */ void job_state_transition(Job *job, JobStatus s1) { @@ -102,6 +122,16 @@ bool job_is_cancelled(Job *job) return job->cancelled; } =20 +bool job_started(Job *job) +{ + return job->co; +} + +bool job_should_pause(Job *job) +{ + return job->pause_count > 0; +} + Job *job_next(Job *job) { if (!job) { @@ -144,6 +174,9 @@ void *job_create(const char *job_id, const JobDriver *d= river, AioContext *ctx, job->id =3D g_strdup(job_id); job->refcnt =3D 1; job->aio_context =3D ctx; + job->busy =3D false; + job->paused =3D true; + job->pause_count =3D 1; =20 job_state_transition(job, JOB_STATUS_CREATED); =20 @@ -173,6 +206,114 @@ void job_unref(Job *job) } } =20 +/* + * Conditionally enter a job pending a call to fn() while under the job_lo= ck + * critical section. + */ +void job_enter_cond(Job *job, bool(*fn)(Job *job)) +{ + if (!job_started(job)) { + return; + } + if (job->deferred_to_main_loop) { + return; + } + + job_lock(); + if (job->busy) { + job_unlock(); + return; + } + + if (fn && !fn(job)) { + job_unlock(); + return; + } + + assert(!job->deferred_to_main_loop); + timer_del(&job->sleep_timer); + job->busy =3D true; + job_unlock(); + aio_co_wake(job->co); +} + +/* Yield, and schedule a timer to reenter the coroutine after @ns nanoseco= nds. + * Reentering the job coroutine with block_job_enter() before the timer has + * expired is allowed and cancels the timer. + * + * If @ns is (uint64_t) -1, no timer is scheduled and block_job_enter() mu= st be + * called explicitly. */ +void coroutine_fn job_do_yield(Job *job, uint64_t ns) +{ + job_lock(); + if (ns !=3D -1) { + timer_mod(&job->sleep_timer, ns); + } + job->busy =3D false; + job_unlock(); + qemu_coroutine_yield(); + + /* Set by job_enter before re-entering the coroutine. */ + assert(job->busy); +} + +void coroutine_fn job_pause_point(Job *job) +{ + assert(job && job_started(job)); + + if (!job_should_pause(job)) { + return; + } + if (job_is_cancelled(job)) { + return; + } + + if (job->driver->pause) { + job->driver->pause(job); + } + + if (job_should_pause(job) && !job_is_cancelled(job)) { + JobStatus status =3D job->status; + job_state_transition(job, status =3D=3D JOB_STATUS_READY + ? JOB_STATUS_STANDBY + : JOB_STATUS_PAUSED); + job->paused =3D true; + job_do_yield(job, -1); + job->paused =3D false; + job_state_transition(job, status); + } + + if (job->driver->resume) { + job->driver->resume(job); + } +} + +/** + * All jobs must allow a pause point before entering their job proper. This + * ensures that jobs can be paused prior to being started, then resumed la= ter. + */ +static void coroutine_fn job_co_entry(void *opaque) +{ + Job *job =3D opaque; + + assert(job && job->driver && job->driver->start); + job_pause_point(job); + job->driver->start(job); +} + + +void job_start(Job *job) +{ + assert(job && !job_started(job) && job->paused && + job->driver && job->driver->start); + job->co =3D qemu_coroutine_create(job_co_entry, job); + job->pause_count--; + job->busy =3D true; + job->paused =3D false; + job_state_transition(job, JOB_STATUS_RUNNING); + aio_co_enter(job->aio_context, job->co); +} + typedef struct { Job *job; JobDeferToMainLoopFn *fn; diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 4f8cba8377..c9f2f9b183 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -524,8 +524,8 @@ BlockJobDriver test_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(TestBlockJob), .free =3D block_job_free, + .start =3D test_job_start, }, - .start =3D test_job_start, .complete =3D test_job_complete, }; =20 @@ -549,47 +549,47 @@ static void test_blockjob_common(enum drain_type drai= n_type) job =3D block_job_create("job0", &test_job_driver, NULL, src, 0, BLK_P= ERM_ALL, 0, 0, NULL, NULL, &error_abort); block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abor= t); - block_job_start(job); + job_start(&job->job); =20 - g_assert_cmpint(job->pause_count, =3D=3D, 0); - g_assert_false(job->paused); - g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ + g_assert_cmpint(job->job.pause_count, =3D=3D, 0); + g_assert_false(job->job.paused); + g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ =20 do_drain_begin(drain_type, src); =20 if (drain_type =3D=3D BDRV_DRAIN_ALL) { /* bdrv_drain_all() drains both src and target */ - g_assert_cmpint(job->pause_count, =3D=3D, 2); + g_assert_cmpint(job->job.pause_count, =3D=3D, 2); } else { - g_assert_cmpint(job->pause_count, =3D=3D, 1); + g_assert_cmpint(job->job.pause_count, =3D=3D, 1); } /* XXX We don't wait until the job is actually paused. Is this okay? */ - /* g_assert_true(job->paused); */ - g_assert_false(job->busy); /* The job is paused */ + /* g_assert_true(job->job.paused); */ + g_assert_false(job->job.busy); /* The job is paused */ =20 do_drain_end(drain_type, src); =20 - g_assert_cmpint(job->pause_count, =3D=3D, 0); - g_assert_false(job->paused); - g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ + g_assert_cmpint(job->job.pause_count, =3D=3D, 0); + g_assert_false(job->job.paused); + g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ =20 do_drain_begin(drain_type, target); =20 if (drain_type =3D=3D BDRV_DRAIN_ALL) { /* bdrv_drain_all() drains both src and target */ - g_assert_cmpint(job->pause_count, =3D=3D, 2); + g_assert_cmpint(job->job.pause_count, =3D=3D, 2); } else { - g_assert_cmpint(job->pause_count, =3D=3D, 1); + g_assert_cmpint(job->job.pause_count, =3D=3D, 1); } /* XXX We don't wait until the job is actually paused. Is this okay? */ - /* g_assert_true(job->paused); */ - g_assert_false(job->busy); /* The job is paused */ + /* g_assert_true(job->job.paused); */ + g_assert_false(job->job.busy); /* The job is paused */ =20 do_drain_end(drain_type, target); =20 - g_assert_cmpint(job->pause_count, =3D=3D, 0); - g_assert_false(job->paused); - g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ + g_assert_cmpint(job->job.pause_count, =3D=3D, 0); + g_assert_false(job->job.paused); + g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ =20 ret =3D block_job_complete_sync(job, &error_abort); g_assert_cmpint(ret, =3D=3D, 0); diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index c03f9662d8..323e154a00 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -78,8 +78,8 @@ static const BlockJobDriver test_block_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(TestBlockJob), .free =3D block_job_free, + .start =3D test_block_job_run, }, - .start =3D test_block_job_run, }; =20 /* Create a block job that completes with a given return code after a given @@ -125,7 +125,7 @@ static void test_single_job(int expected) =20 txn =3D block_job_txn_new(); job =3D test_block_job_start(1, true, expected, &result, txn); - block_job_start(job); + job_start(&job->job); =20 if (expected =3D=3D -ECANCELED) { block_job_cancel(job, false); @@ -165,8 +165,8 @@ static void test_pair_jobs(int expected1, int expected2) txn =3D block_job_txn_new(); job1 =3D test_block_job_start(1, true, expected1, &result1, txn); job2 =3D test_block_job_start(2, true, expected2, &result2, txn); - block_job_start(job1); - block_job_start(job2); + job_start(&job1->job); + job_start(&job2->job); =20 /* Release our reference now to trigger as many nice * use-after-free bugs as possible. @@ -227,8 +227,8 @@ static void test_pair_jobs_fail_cancel_race(void) txn =3D block_job_txn_new(); job1 =3D test_block_job_start(1, true, -ECANCELED, &result1, txn); job2 =3D test_block_job_start(2, false, 0, &result2, txn); - block_job_start(job1); - block_job_start(job2); + job_start(&job1->job); + job_start(&job2->job); =20 block_job_cancel(job1, false); =20 diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 5f43bd72a4..1d18325feb 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -199,8 +199,8 @@ static const BlockJobDriver test_cancel_driver =3D { .job_driver =3D { .instance_size =3D sizeof(CancelJob), .free =3D block_job_free, + .start =3D cancel_job_start, }, - .start =3D cancel_job_start, .complete =3D cancel_job_complete, }; =20 @@ -254,7 +254,7 @@ static void test_cancel_running(void) =20 s =3D create_common(&job); =20 - block_job_start(job); + job_start(&job->job); assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 cancel_common(s); @@ -267,7 +267,7 @@ static void test_cancel_paused(void) =20 s =3D create_common(&job); =20 - block_job_start(job); + job_start(&job->job); assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 block_job_user_pause(job, &error_abort); @@ -284,7 +284,7 @@ static void test_cancel_ready(void) =20 s =3D create_common(&job); =20 - block_job_start(job); + job_start(&job->job); assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; @@ -301,7 +301,7 @@ static void test_cancel_standby(void) =20 s =3D create_common(&job); =20 - block_job_start(job); + job_start(&job->job); assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; @@ -322,7 +322,7 @@ static void test_cancel_pending(void) =20 s =3D create_common(&job); =20 - block_job_start(job); + job_start(&job->job); assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; @@ -346,7 +346,7 @@ static void test_cancel_concluded(void) =20 s =3D create_common(&job); =20 - block_job_start(job); + job_start(&job->job); assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584204095322.3909726553934; Tue, 24 Apr 2018 08:36:44 -0700 (PDT) Received: from localhost ([::1]:59144 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzzn-00087o-3y for importer@patchew.org; Tue, 24 Apr 2018 11:36:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47948) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpK-000882-8v for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpI-0008GM-BA for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:54 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34850 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpD-00089L-0P; Tue, 24 Apr 2018 11:25:47 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 92DD4738E0; Tue, 24 Apr 2018 15:25:46 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 841CD202323A; Tue, 24 Apr 2018 15:25:45 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:00 +0200 Message-Id: <20180424152515.25664-19-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:46 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:46 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 18/33] job: Add job_sleep_ns() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" There is nothing block layer specific about block_job_sleep_ns(), so move the function to Job. Signed-off-by: Kevin Wolf --- include/block/blockjob_int.h | 11 ----------- include/qemu/job.h | 17 +++++++++++++++++ block/backup.c | 2 +- block/commit.c | 2 +- block/mirror.c | 4 ++-- block/stream.c | 2 +- blockjob.c | 27 --------------------------- job.c | 32 ++++++++++++++++++++++++++++++++ tests/test-bdrv-drain.c | 8 ++++---- tests/test-blockjob-txn.c | 2 +- tests/test-blockjob.c | 2 +- 11 files changed, 60 insertions(+), 49 deletions(-) diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 8bf7fbc94a..22177fb3ab 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -134,17 +134,6 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, void block_job_free(Job *job); =20 /** - * block_job_sleep_ns: - * @job: The job that calls the function. - * @ns: How many nanoseconds to stop for. - * - * Put the job to sleep (assuming that it wasn't canceled) for @ns - * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately - * interrupt the wait. - */ -void block_job_sleep_ns(BlockJob *job, int64_t ns); - -/** * block_job_yield: * @job: The job that calls the function. * diff --git a/include/qemu/job.h b/include/qemu/job.h index 8e636ba970..e60d4b23cc 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -161,6 +161,13 @@ void job_unref(Job *job); void job_start(Job *job); =20 /** + * @job: The job to enter. + * + * Continue the specified job by entering the coroutine. + */ +void job_enter(Job *job); + +/** * @job: The job that is ready to pause. * * Pause now if job_pause() has been called. Jobs that perform lots of I/O @@ -168,6 +175,16 @@ void job_start(Job *job); */ void coroutine_fn job_pause_point(Job *job); =20 +/** + * @job: The job that calls the function. + * @ns: How many nanoseconds to stop for. + * + * Put the job to sleep (assuming that it wasn't canceled) for @ns + * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately + * interrupt the wait. + */ +void coroutine_fn job_sleep_ns(Job *job, int64_t ns); + =20 /** Returns the JobType of a given Job. */ JobType job_type(Job *job); diff --git a/block/backup.c b/block/backup.c index f81c137050..6f14476501 100644 --- a/block/backup.c +++ b/block/backup.c @@ -338,7 +338,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob= *job) * (without it, the VM does not reboot) */ delay_ns =3D block_job_ratelimit_get_delay(&job->common, job->bytes_re= ad); job->bytes_read =3D 0; - block_job_sleep_ns(&job->common, delay_ns); + job_sleep_ns(&job->common.job, delay_ns); =20 if (job_is_cancelled(&job->common.job)) { return true; diff --git a/block/commit.c b/block/commit.c index 2fbc31077a..1c6cb6c298 100644 --- a/block/commit.c +++ b/block/commit.c @@ -172,7 +172,7 @@ static void coroutine_fn commit_run(void *opaque) /* Note that even when no rate limit is applied we need to yield * with no pending I/O here so that bdrv_drain_all() returns. */ - block_job_sleep_ns(&s->common, delay_ns); + job_sleep_ns(&s->common.job, delay_ns); if (job_is_cancelled(&s->common.job)) { break; } diff --git a/block/mirror.c b/block/mirror.c index 36f21f6e7d..26f2c774ce 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -595,7 +595,7 @@ static void mirror_throttle(MirrorBlockJob *s) =20 if (now - s->last_pause_ns > SLICE_TIME) { s->last_pause_ns =3D now; - block_job_sleep_ns(&s->common, 0); + job_sleep_ns(&s->common.job, 0); } else { job_pause_point(&s->common.job); } @@ -869,7 +869,7 @@ static void coroutine_fn mirror_run(void *opaque) break; } else if (!should_complete) { delay_ns =3D (s->in_flight =3D=3D 0 && cnt =3D=3D 0 ? SLICE_TI= ME : 0); - block_job_sleep_ns(&s->common, delay_ns); + job_sleep_ns(&s->common.job, delay_ns); } s->last_pause_ns =3D qemu_clock_get_ns(QEMU_CLOCK_REALTIME); } diff --git a/block/stream.c b/block/stream.c index 6d8b7b6eee..1faab02086 100644 --- a/block/stream.c +++ b/block/stream.c @@ -140,7 +140,7 @@ static void coroutine_fn stream_run(void *opaque) /* Note that even when no rate limit is applied we need to yield * with no pending I/O here so that bdrv_drain_all() returns. */ - block_job_sleep_ns(&s->common, delay_ns); + job_sleep_ns(&s->common.job, delay_ns); if (job_is_cancelled(&s->common.job)) { break; } diff --git a/blockjob.c b/blockjob.c index ca4d50aaef..4ce4dd83a6 100644 --- a/blockjob.c +++ b/blockjob.c @@ -174,7 +174,6 @@ void block_job_free(Job *job) block_job_detach_aio_context, bjob); blk_unref(bjob->blk); error_free(bjob->blocker); - assert(!timer_pending(&bjob->job.sleep_timer)); } =20 static void block_job_attached_aio_context(AioContext *new_context, @@ -283,13 +282,6 @@ const BlockJobDriver *block_job_driver(BlockJob *job) return job->driver; } =20 -static void block_job_sleep_timer_cb(void *opaque) -{ - BlockJob *job =3D opaque; - - block_job_enter(job); -} - static void block_job_decommission(BlockJob *job) { assert(job); @@ -857,9 +849,6 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, job->opaque =3D opaque; job->auto_finalize =3D !(flags & BLOCK_JOB_MANUAL_FINALIZE); job->auto_dismiss =3D !(flags & BLOCK_JOB_MANUAL_DISMISS); - aio_timer_init(qemu_get_aio_context(), &job->job.sleep_timer, - QEMU_CLOCK_REALTIME, SCALE_NS, - block_job_sleep_timer_cb, job); =20 error_setg(&job->blocker, "block device is in use by block job: %s", job_type_str(&job->job)); @@ -922,22 +911,6 @@ void block_job_enter(BlockJob *job) job_enter_cond(&job->job, NULL); } =20 -void block_job_sleep_ns(BlockJob *job, int64_t ns) -{ - assert(job->job.busy); - - /* Check cancellation *before* setting busy =3D false, too! */ - if (job_is_cancelled(&job->job)) { - return; - } - - if (!job_should_pause(&job->job)) { - job_do_yield(&job->job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + n= s); - } - - job_pause_point(&job->job); -} - void block_job_yield(BlockJob *job) { assert(job->job.busy); diff --git a/job.c b/job.c index ea4ee8a325..d52f5586dc 100644 --- a/job.c +++ b/job.c @@ -153,6 +153,13 @@ Job *job_get(const char *id) return NULL; } =20 +static void job_sleep_timer_cb(void *opaque) +{ + Job *job =3D opaque; + + job_enter(job); +} + void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, Error **errp) { @@ -179,6 +186,9 @@ void *job_create(const char *job_id, const JobDriver *d= river, AioContext *ctx, job->pause_count =3D 1; =20 job_state_transition(job, JOB_STATUS_CREATED); + aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, + QEMU_CLOCK_REALTIME, SCALE_NS, + job_sleep_timer_cb, job); =20 QLIST_INSERT_HEAD(&jobs, job, job_list); =20 @@ -194,6 +204,7 @@ void job_unref(Job *job) { if (--job->refcnt =3D=3D 0) { assert(job->status =3D=3D JOB_STATUS_NULL); + assert(!timer_pending(&job->sleep_timer)); =20 if (job->driver->free) { job->driver->free(job); @@ -237,6 +248,11 @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)) aio_co_wake(job->co); } =20 +void job_enter(Job *job) +{ + job_enter_cond(job, NULL); +} + /* Yield, and schedule a timer to reenter the coroutine after @ns nanoseco= nds. * Reentering the job coroutine with block_job_enter() before the timer has * expired is allowed and cancels the timer. @@ -288,6 +304,22 @@ void coroutine_fn job_pause_point(Job *job) } } =20 +void coroutine_fn job_sleep_ns(Job *job, int64_t ns) +{ + assert(job->busy); + + /* Check cancellation *before* setting busy =3D false, too! */ + if (job_is_cancelled(job)) { + return; + } + + if (!job_should_pause(job)) { + job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); + } + + job_pause_point(job); +} + /** * All jobs must allow a pause point before entering their job proper. This * ensures that jobs can be paused prior to being started, then resumed la= ter. diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index c9f2f9b183..50232f5eaf 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -508,7 +508,7 @@ static void coroutine_fn test_job_start(void *opaque) =20 block_job_event_ready(&s->common); while (!s->should_complete) { - block_job_sleep_ns(&s->common, 100000); + job_sleep_ns(&s->common.job, 100000); } =20 job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); @@ -553,7 +553,7 @@ static void test_blockjob_common(enum drain_type drain_= type) =20 g_assert_cmpint(job->job.pause_count, =3D=3D, 0); g_assert_false(job->job.paused); - g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ + g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ =20 do_drain_begin(drain_type, src); =20 @@ -571,7 +571,7 @@ static void test_blockjob_common(enum drain_type drain_= type) =20 g_assert_cmpint(job->job.pause_count, =3D=3D, 0); g_assert_false(job->job.paused); - g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ + g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ =20 do_drain_begin(drain_type, target); =20 @@ -589,7 +589,7 @@ static void test_blockjob_common(enum drain_type drain_= type) =20 g_assert_cmpint(job->job.pause_count, =3D=3D, 0); g_assert_false(job->job.paused); - g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ + g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ =20 ret =3D block_job_complete_sync(job, &error_abort); g_assert_cmpint(ret, =3D=3D, 0); diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 323e154a00..0e6162bc71 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -45,7 +45,7 @@ static void coroutine_fn test_block_job_run(void *opaque) =20 while (s->iterations--) { if (s->use_timer) { - block_job_sleep_ns(job, 0); + job_sleep_ns(&job->job, 0); } else { block_job_yield(job); } diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 1d18325feb..b329bd5274 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -188,7 +188,7 @@ static void coroutine_fn cancel_job_start(void *opaque) block_job_event_ready(&s->common); } =20 - block_job_sleep_ns(&s->common, 100000); + job_sleep_ns(&s->common.job, 100000); } =20 defer: --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585078994531.2231231259002; Tue, 24 Apr 2018 08:51:18 -0700 (PDT) Received: from localhost ([::1]:59238 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Dt-0002ld-Um for importer@patchew.org; Tue, 24 Apr 2018 11:51:18 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48064) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpP-0008D8-N0 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpN-0008MY-3f for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:59 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59838 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpE-0008BO-B9; Tue, 24 Apr 2018 11:25:48 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DE6FF406C7AC; Tue, 24 Apr 2018 15:25:47 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id CEE6C202342F; Tue, 24 Apr 2018 15:25:46 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:01 +0200 Message-Id: <20180424152515.25664-20-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:47 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:47 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 19/33] job: Move pause/resume functions to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" While we already moved the state related to job pausing to Job, the functions to do were still BlockJob only. This commit moves them over to Job. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 32 ------------------- include/block/blockjob_int.h | 7 +++++ include/qemu/job.h | 29 ++++++++++++++++++ block/backup.c | 1 + block/commit.c | 1 + block/mirror.c | 2 ++ block/stream.c | 1 + blockdev.c | 6 ++-- blockjob.c | 73 ++++++++++------------------------------= ---- job.c | 51 +++++++++++++++++++++++++++++++ tests/test-bdrv-drain.c | 1 + tests/test-blockjob-txn.c | 1 + tests/test-blockjob.c | 6 ++-- 13 files changed, 117 insertions(+), 94 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index c0448206e2..ce136ff2ac 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -57,12 +57,6 @@ typedef struct BlockJob { bool force; =20 /** - * Set to true if the job is paused by user. Can be unpaused with the - * block-job-resume QMP command. - */ - bool user_paused; - - /** * Set to true when the job is ready to be completed. */ bool ready; @@ -248,32 +242,6 @@ void block_job_progress_set_remaining(BlockJob *job, u= int64_t remaining); BlockJobInfo *block_job_query(BlockJob *job, Error **errp); =20 /** - * block_job_user_pause: - * @job: The job to be paused. - * - * Asynchronously pause the specified job. - * Do not allow a resume until a matching call to block_job_user_resume. - */ -void block_job_user_pause(BlockJob *job, Error **errp); - -/** - * block_job_paused: - * @job: The job to query. - * - * Returns true if the job is user-paused. - */ -bool block_job_user_paused(BlockJob *job); - -/** - * block_job_user_resume: - * @job: The job to be resumed. - * - * Resume the specified job. - * Must be paired with a preceding block_job_user_pause. - */ -void block_job_user_resume(BlockJob *job, Error **errp); - -/** * block_job_user_cancel: * @job: The job to be cancelled. * @force: Quit a job without waiting for data to be in sync. diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 22177fb3ab..ca0610f967 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -134,6 +134,13 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, void block_job_free(Job *job); =20 /** + * block_job_user_resume: + * Callback to be used for JobDriver.user_resume in all block jobs. Resets= the + * iostatus when the user resumes @job. + */ +void block_job_user_resume(Job *job); + +/** * block_job_yield: * @job: The job that calls the function. * diff --git a/include/qemu/job.h b/include/qemu/job.h index e60d4b23cc..54adb29958 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -83,6 +83,12 @@ typedef struct Job { bool paused; =20 /** + * Set to true if the job is paused by user. Can be unpaused with the + * block-job-resume QMP command. + */ + bool user_paused; + + /** * Set to true if the job should cancel itself. The flag must * always be tested just before toggling the busy flag from false * to true. After a job has been cancelled, it should only yield @@ -124,6 +130,12 @@ struct JobDriver { */ void coroutine_fn (*resume)(Job *job); =20 + /** + * Called when the job is resumed by the user (i.e. user_paused becomes + * false). .user_resume is called before .resume. + */ + void (*user_resume)(Job *job); + /** Called when the job is freed */ void (*free)(Job *job); }; @@ -196,6 +208,21 @@ const char *job_type_str(Job *job); bool job_is_cancelled(Job *job); =20 /** + * Asynchronously pause the specified @job. + * Do not allow a resume until a matching call to job_user_resume. + */ +void job_user_pause(Job *job, Error **errp); + +/** Returns true if the job is user-paused. */ +bool job_user_paused(Job *job); + +/** + * Resume the specified @job. + * Must be paired with a preceding job_user_pause. + */ +void job_user_resume(Job *job, Error **errp); + +/** * Get the next element from the list of block jobs after @job, or the * first one if @job is %NULL. * @@ -234,5 +261,7 @@ void coroutine_fn job_do_yield(Job *job, uint64_t ns); bool job_should_pause(Job *job); bool job_started(Job *job); void job_enter_cond(Job *job, bool(*fn)(Job *job)); +void job_pause(Job *job); +void job_resume(Job *job); =20 #endif diff --git a/block/backup.c b/block/backup.c index 6f14476501..eca4f764c4 100644 --- a/block/backup.c +++ b/block/backup.c @@ -528,6 +528,7 @@ static const BlockJobDriver backup_job_driver =3D { .instance_size =3D sizeof(BackupBlockJob), .job_type =3D JOB_TYPE_BACKUP, .free =3D block_job_free, + .user_resume =3D block_job_user_resume, .start =3D backup_run, }, .commit =3D backup_commit, diff --git a/block/commit.c b/block/commit.c index 1c6cb6c298..c4a98e5804 100644 --- a/block/commit.c +++ b/block/commit.c @@ -220,6 +220,7 @@ static const BlockJobDriver commit_job_driver =3D { .instance_size =3D sizeof(CommitBlockJob), .job_type =3D JOB_TYPE_COMMIT, .free =3D block_job_free, + .user_resume =3D block_job_user_resume, .start =3D commit_run, }, }; diff --git a/block/mirror.c b/block/mirror.c index 26f2c774ce..876b636121 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -987,6 +987,7 @@ static const BlockJobDriver mirror_job_driver =3D { .instance_size =3D sizeof(MirrorBlockJob), .job_type =3D JOB_TYPE_MIRROR, .free =3D block_job_free, + .user_resume =3D block_job_user_resume, .start =3D mirror_run, .pause =3D mirror_pause, }, @@ -1000,6 +1001,7 @@ static const BlockJobDriver commit_active_job_driver = =3D { .instance_size =3D sizeof(MirrorBlockJob), .job_type =3D JOB_TYPE_COMMIT, .free =3D block_job_free, + .user_resume =3D block_job_user_resume, .start =3D mirror_run, .pause =3D mirror_pause, }, diff --git a/block/stream.c b/block/stream.c index 1faab02086..e81b488a22 100644 --- a/block/stream.c +++ b/block/stream.c @@ -214,6 +214,7 @@ static const BlockJobDriver stream_job_driver =3D { .job_type =3D JOB_TYPE_STREAM, .free =3D block_job_free, .start =3D stream_run, + .user_resume =3D block_job_user_resume, }, }; =20 diff --git a/blockdev.c b/blockdev.c index 44471b28d7..891cbe9940 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3844,7 +3844,7 @@ void qmp_block_job_cancel(const char *device, force =3D false; } =20 - if (block_job_user_paused(job) && !force) { + if (job_user_paused(&job->job) && !force) { error_setg(errp, "The block job for device '%s' is currently pause= d", device); goto out; @@ -3866,7 +3866,7 @@ void qmp_block_job_pause(const char *device, Error **= errp) } =20 trace_qmp_block_job_pause(job); - block_job_user_pause(job, errp); + job_user_pause(&job->job, errp); aio_context_release(aio_context); } =20 @@ -3880,7 +3880,7 @@ void qmp_block_job_resume(const char *device, Error *= *errp) } =20 trace_qmp_block_job_resume(job); - block_job_user_resume(job, errp); + job_user_resume(&job->job, errp); aio_context_release(aio_context); } =20 diff --git a/blockjob.c b/blockjob.c index 4ce4dd83a6..cace95990f 100644 --- a/blockjob.c +++ b/blockjob.c @@ -141,21 +141,6 @@ static void block_job_txn_del_job(BlockJob *job) } } =20 -static void block_job_pause(BlockJob *job) -{ - job->job.pause_count++; -} - -static void block_job_resume(BlockJob *job) -{ - assert(job->job.pause_count > 0); - job->job.pause_count--; - if (job->job.pause_count) { - return; - } - block_job_enter(job); -} - static void block_job_attached_aio_context(AioContext *new_context, void *opaque); static void block_job_detach_aio_context(void *opaque); @@ -186,7 +171,7 @@ static void block_job_attached_aio_context(AioContext *= new_context, job->driver->attached_aio_context(job, new_context); } =20 - block_job_resume(job); + job_resume(&job->job); } =20 static void block_job_drain(BlockJob *job) @@ -207,7 +192,7 @@ static void block_job_detach_aio_context(void *opaque) /* In case the job terminates during aio_poll()... */ job_ref(&job->job); =20 - block_job_pause(job); + job_pause(&job->job); =20 while (!job->job.paused && !job->completed) { block_job_drain(job); @@ -226,13 +211,13 @@ static char *child_job_get_parent_desc(BdrvChild *c) static void child_job_drained_begin(BdrvChild *c) { BlockJob *job =3D c->opaque; - block_job_pause(job); + job_pause(&job->job); } =20 static void child_job_drained_end(BdrvChild *c) { BlockJob *job =3D c->opaque; - block_job_resume(job); + job_resume(&job->job); } =20 static const BdrvChildRole child_job =3D { @@ -389,9 +374,9 @@ static void block_job_cancel_async(BlockJob *job, bool = force) if (job->iostatus !=3D BLOCK_DEVICE_IO_STATUS_OK) { block_job_iostatus_reset(job); } - if (job->user_paused) { + if (job->job.user_paused) { /* Do not call block_job_enter here, the caller will handle it. */ - job->user_paused =3D false; + job->job.user_paused =3D false; job->job.pause_count--; } job->job.cancelled =3D true; @@ -621,39 +606,6 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) *jobptr =3D NULL; } =20 -void block_job_user_pause(BlockJob *job, Error **errp) -{ - if (job_apply_verb(&job->job, JOB_VERB_PAUSE, errp)) { - return; - } - if (job->user_paused) { - error_setg(errp, "Job is already paused"); - return; - } - job->user_paused =3D true; - block_job_pause(job); -} - -bool block_job_user_paused(BlockJob *job) -{ - return job->user_paused; -} - -void block_job_user_resume(BlockJob *job, Error **errp) -{ - assert(job); - if (!job->user_paused || job->job.pause_count <=3D 0) { - error_setg(errp, "Can't resume a job that was not paused"); - return; - } - if (job_apply_verb(&job->job, JOB_VERB_RESUME, errp)) { - return; - } - block_job_iostatus_reset(job); - job->user_paused =3D false; - block_job_resume(job); -} - void block_job_cancel(BlockJob *job, bool force) { if (job->job.status =3D=3D JOB_STATUS_CONCLUDED) { @@ -842,6 +794,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, =20 assert(is_block_job(&job->job)); assert(job->job.driver->free =3D=3D &block_job_free); + assert(job->job.driver->user_resume =3D=3D &block_job_user_resume); =20 job->driver =3D driver; job->blk =3D blk; @@ -932,10 +885,16 @@ void block_job_iostatus_reset(BlockJob *job) if (job->iostatus =3D=3D BLOCK_DEVICE_IO_STATUS_OK) { return; } - assert(job->user_paused && job->job.pause_count > 0); + assert(job->job.user_paused && job->job.pause_count > 0); job->iostatus =3D BLOCK_DEVICE_IO_STATUS_OK; } =20 +void block_job_user_resume(Job *job) +{ + BlockJob *bjob =3D container_of(job, BlockJob, job); + block_job_iostatus_reset(bjob); +} + void block_job_event_ready(BlockJob *job) { job_state_transition(&job->job, JOB_STATUS_READY); @@ -982,9 +941,9 @@ BlockErrorAction block_job_error_action(BlockJob *job, = BlockdevOnError on_err, action, &error_abort); } if (action =3D=3D BLOCK_ERROR_ACTION_STOP) { - block_job_pause(job); + job_pause(&job->job); /* make the pause user visible, which will be resumed from QMP. */ - job->user_paused =3D true; + job->job.user_paused =3D true; block_job_iostatus_set_err(job, error); } return action; diff --git a/job.c b/job.c index d52f5586dc..67b0405d9d 100644 --- a/job.c +++ b/job.c @@ -346,6 +346,57 @@ void job_start(Job *job) aio_co_enter(job->aio_context, job->co); } =20 +void job_pause(Job *job) +{ + job->pause_count++; +} + +void job_resume(Job *job) +{ + assert(job->pause_count > 0); + job->pause_count--; + if (job->pause_count) { + return; + } + job_enter(job); +} + +void job_user_pause(Job *job, Error **errp) +{ + if (job_apply_verb(job, JOB_VERB_PAUSE, errp)) { + return; + } + if (job->user_paused) { + error_setg(errp, "Job is already paused"); + return; + } + job->user_paused =3D true; + job_pause(job); +} + +bool job_user_paused(Job *job) +{ + return job->user_paused; +} + +void job_user_resume(Job *job, Error **errp) +{ + assert(job); + if (!job->user_paused || job->pause_count <=3D 0) { + error_setg(errp, "Can't resume a job that was not paused"); + return; + } + if (job_apply_verb(job, JOB_VERB_RESUME, errp)) { + return; + } + if (job->driver->user_resume) { + job->driver->user_resume(job); + } + job->user_paused =3D false; + job_resume(job); +} + + typedef struct { Job *job; JobDeferToMainLoopFn *fn; diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 50232f5eaf..c993512f66 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -524,6 +524,7 @@ BlockJobDriver test_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(TestBlockJob), .free =3D block_job_free, + .user_resume =3D block_job_user_resume, .start =3D test_job_start, }, .complete =3D test_job_complete, diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 0e6162bc71..93d1ff0859 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -78,6 +78,7 @@ static const BlockJobDriver test_block_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(TestBlockJob), .free =3D block_job_free, + .user_resume =3D block_job_user_resume, .start =3D test_block_job_run, }, }; diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index b329bd5274..ceb59600ed 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -20,6 +20,7 @@ static const BlockJobDriver test_block_job_driver =3D { .job_driver =3D { .instance_size =3D sizeof(BlockJob), .free =3D block_job_free, + .user_resume =3D block_job_user_resume, }, }; =20 @@ -199,6 +200,7 @@ static const BlockJobDriver test_cancel_driver =3D { .job_driver =3D { .instance_size =3D sizeof(CancelJob), .free =3D block_job_free, + .user_resume =3D block_job_user_resume, .start =3D cancel_job_start, }, .complete =3D cancel_job_complete, @@ -270,7 +272,7 @@ static void test_cancel_paused(void) job_start(&job->job); assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 - block_job_user_pause(job, &error_abort); + job_user_pause(&job->job, &error_abort); block_job_enter(job); assert(job->job.status =3D=3D JOB_STATUS_PAUSED); =20 @@ -308,7 +310,7 @@ static void test_cancel_standby(void) block_job_enter(job); assert(job->job.status =3D=3D JOB_STATUS_READY); =20 - block_job_user_pause(job, &error_abort); + job_user_pause(&job->job, &error_abort); block_job_enter(job); assert(job->job.status =3D=3D JOB_STATUS_STANDBY); =20 --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585617740682.9691505055227; Tue, 24 Apr 2018 09:00:17 -0700 (PDT) Received: from localhost ([::1]:59297 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Ma-00021v-PV for importer@patchew.org; Tue, 24 Apr 2018 12:00:16 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48003) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpN-0008AJ-78 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpL-0008LH-Sj for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:57 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34852 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpF-0008Dq-J9; Tue, 24 Apr 2018 11:25:49 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3522AFB677; Tue, 24 Apr 2018 15:25:49 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 261742026990; Tue, 24 Apr 2018 15:25:48 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:02 +0200 Message-Id: <20180424152515.25664-21-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:49 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:49 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 20/33] job: Replace BlockJob.completed with job_is_completed() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Since we introduced an explicit status to block job, BlockJob.completed is redundant because it can be derived from the status. Remove the field from BlockJob and add a function to derive it from the status at the Job level. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 3 --- include/qemu/job.h | 3 +++ blockjob.c | 16 +++++++--------- job.c | 22 ++++++++++++++++++++++ qemu-img.c | 4 ++-- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index ce136ff2ac..a2d16a700d 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -88,9 +88,6 @@ typedef struct BlockJob { /** The opaque value that is passed to the completion function. */ void *opaque; =20 - /** True when job has reported completion by calling block_job_complet= ed. */ - bool completed; - /** ret code passed to block_job_completed. */ int ret; =20 diff --git a/include/qemu/job.h b/include/qemu/job.h index 54adb29958..fd4937ee8d 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -207,6 +207,9 @@ const char *job_type_str(Job *job); /** Returns whether the job is scheduled for cancellation. */ bool job_is_cancelled(Job *job); =20 +/** Returns whether the job is in a completed state. */ +bool job_is_completed(Job *job); + /** * Asynchronously pause the specified @job. * Do not allow a resume until a matching call to job_user_resume. diff --git a/blockjob.c b/blockjob.c index cace95990f..54e74c5a76 100644 --- a/blockjob.c +++ b/blockjob.c @@ -194,7 +194,7 @@ static void block_job_detach_aio_context(void *opaque) =20 job_pause(&job->job); =20 - while (!job->job.paused && !job->completed) { + while (!job->job.paused && !job_is_completed(&job->job)) { block_job_drain(job); } =20 @@ -270,7 +270,6 @@ const BlockJobDriver *block_job_driver(BlockJob *job) static void block_job_decommission(BlockJob *job) { assert(job); - job->completed =3D true; job->job.busy =3D false; job->job.paused =3D false; job->job.deferred_to_main_loop =3D true; @@ -335,7 +334,7 @@ static void block_job_clean(BlockJob *job) =20 static int block_job_finalize_single(BlockJob *job) { - assert(job->completed); + assert(job_is_completed(&job->job)); =20 /* Ensure abort is called for late-transactional failures */ block_job_update_rc(job); @@ -428,10 +427,10 @@ static int block_job_finish_sync(BlockJob *job, /* block_job_drain calls block_job_enter, and it should be enough to * induce progress until the job completes or moves to the main thread. */ - while (!job->job.deferred_to_main_loop && !job->completed) { + while (!job->job.deferred_to_main_loop && !job_is_completed(&job->job)= ) { block_job_drain(job); } - while (!job->completed) { + while (!job_is_completed(&job->job)) { aio_poll(qemu_get_aio_context(), true); } ret =3D (job_is_cancelled(&job->job) && job->ret =3D=3D 0) @@ -472,7 +471,7 @@ static void block_job_completed_txn_abort(BlockJob *job) while (!QLIST_EMPTY(&txn->jobs)) { other_job =3D QLIST_FIRST(&txn->jobs); ctx =3D blk_get_aio_context(other_job->blk); - if (!other_job->completed) { + if (!job_is_completed(&other_job->job)) { assert(job_is_cancelled(&other_job->job)); block_job_finish_sync(other_job, NULL, NULL); } @@ -514,7 +513,7 @@ static void block_job_completed_txn_success(BlockJob *j= ob) * txn. */ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - if (!other_job->completed) { + if (!job_is_completed(&other_job->job)) { return; } assert(other_job->ret =3D=3D 0); @@ -846,9 +845,8 @@ void block_job_early_fail(BlockJob *job) =20 void block_job_completed(BlockJob *job, int ret) { - assert(job && job->txn && !job->completed); + assert(job && job->txn && !job_is_completed(&job->job)); assert(blk_bs(job->blk)->job =3D=3D job); - job->completed =3D true; job->ret =3D ret; block_job_update_rc(job); trace_block_job_completed(job, ret, job->ret); diff --git a/job.c b/job.c index 67b0405d9d..92157e59ea 100644 --- a/job.c +++ b/job.c @@ -122,6 +122,28 @@ bool job_is_cancelled(Job *job) return job->cancelled; } =20 +bool job_is_completed(Job *job) +{ + switch (job->status) { + case JOB_STATUS_UNDEFINED: + case JOB_STATUS_CREATED: + case JOB_STATUS_RUNNING: + case JOB_STATUS_PAUSED: + case JOB_STATUS_READY: + case JOB_STATUS_STANDBY: + return false; + case JOB_STATUS_WAITING: + case JOB_STATUS_PENDING: + case JOB_STATUS_ABORTING: + case JOB_STATUS_CONCLUDED: + case JOB_STATUS_NULL: + return true; + default: + g_assert_not_reached(); + } + return false; +} + bool job_started(Job *job) { return job->co; diff --git a/qemu-img.c b/qemu-img.c index 62a52edc34..081b03fd91 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -867,9 +867,9 @@ static void run_block_job(BlockJob *job, Error **errp) aio_poll(aio_context, true); qemu_progress_print(job->len ? ((float)job->offset / job->len * 100.f) : 0.0f= , 0); - } while (!job->ready && !job->completed); + } while (!job->ready && !job_is_completed(&job->job)); =20 - if (!job->completed) { + if (!job_is_completed(&job->job)) { ret =3D block_job_complete_sync(job, errp); } else { ret =3D job->ret; --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524586352722216.1621230000045; Tue, 24 Apr 2018 09:12:32 -0700 (PDT) Received: from localhost ([::1]:59387 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0YN-0003IR-K4 for importer@patchew.org; Tue, 24 Apr 2018 12:12:27 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48040) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpO-0008Bh-D1 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpM-0008LT-0w for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:58 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34856 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpG-0008F7-TL; Tue, 24 Apr 2018 11:25:51 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 81CEEFE5CA; Tue, 24 Apr 2018 15:25:50 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 706F2202342F; Tue, 24 Apr 2018 15:25:49 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:03 +0200 Message-Id: <20180424152515.25664-22-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:50 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:50 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 21/33] job: Move BlockJobCreateFlags to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This renames the BlockJobCreateFlags constants, moves a few JOB_INTERNAL checks to job_create() and the auto_{finalize,dismiss} fields from BlockJob to Job. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 17 ----------------- include/block/blockjob_int.h | 3 +-- include/qemu/job.h | 20 +++++++++++++++++++- block/commit.c | 2 +- block/mirror.c | 2 +- block/replication.c | 4 ++-- block/stream.c | 2 +- blockdev.c | 14 +++++++------- blockjob.c | 27 +++++++-------------------- job.c | 11 ++++++++++- qemu-img.c | 2 +- tests/test-blockjob-txn.c | 2 +- tests/test-blockjob.c | 4 ++-- 13 files changed, 53 insertions(+), 57 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index a2d16a700d..a74d5d02fd 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -91,27 +91,10 @@ typedef struct BlockJob { /** ret code passed to block_job_completed. */ int ret; =20 - /** True if this job should automatically finalize itself */ - bool auto_finalize; - - /** True if this job should automatically dismiss itself */ - bool auto_dismiss; - BlockJobTxn *txn; QLIST_ENTRY(BlockJob) txn_list; } BlockJob; =20 -typedef enum BlockJobCreateFlags { - /* Default behavior */ - BLOCK_JOB_DEFAULT =3D 0x00, - /* BlockJob is not QMP-created and should not send QMP events */ - BLOCK_JOB_INTERNAL =3D 0x01, - /* BlockJob requires manual finalize step */ - BLOCK_JOB_MANUAL_FINALIZE =3D 0x02, - /* BlockJob requires manual dismiss step */ - BLOCK_JOB_MANUAL_DISMISS =3D 0x04, -} BlockJobCreateFlags; - /** * block_job_next: * @job: A block job, or %NULL. diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index ca0610f967..543ca556fc 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -106,8 +106,7 @@ struct BlockJobDriver { * @bs: The block * @perm, @shared_perm: Permissions to request for @bs * @speed: The maximum speed, in bytes per second, or 0 for unlimited. - * @flags: Creation flags for the Block Job. - * See @BlockJobCreateFlags + * @flags: Creation flags for the Block Job. See @JobCreateFlags. * @cb: Completion function for the job. * @opaque: Opaque pointer value passed to @cb. * @errp: Error object. diff --git a/include/qemu/job.h b/include/qemu/job.h index fd4937ee8d..ab3d49685a 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -99,6 +99,12 @@ typedef struct Job { /** Set to true when the job has deferred work to the main loop. */ bool deferred_to_main_loop; =20 + /** True if this job should automatically finalize itself */ + bool auto_finalize; + + /** True if this job should automatically dismiss itself */ + bool auto_dismiss; + /** Element of the list of jobs */ QLIST_ENTRY(Job) job_list; } Job; @@ -140,6 +146,17 @@ struct JobDriver { void (*free)(Job *job); }; =20 +typedef enum JobCreateFlags { + /* Default behavior */ + JOB_DEFAULT =3D 0x00, + /* Job is not QMP-created and should not send QMP events */ + JOB_INTERNAL =3D 0x01, + /* Job requires manual finalize step */ + JOB_MANUAL_FINALIZE =3D 0x02, + /* Job requires manual dismiss step */ + JOB_MANUAL_DISMISS =3D 0x04, +} JobCreateFlags; + =20 /** * Create a new long-running job and return it. @@ -147,10 +164,11 @@ struct JobDriver { * @job_id: The id of the newly-created job, or %NULL for internal jobs * @driver: The class object for the newly-created job. * @ctx: The AioContext to run the job coroutine in. + * @flags: Creation flags for the job. See @JobCreateFlags. * @errp: Error object. */ void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, - Error **errp); + int flags, Error **errp); =20 /** * Add a reference to Job refcnt, it will be decreased with job_unref, and= then diff --git a/block/commit.c b/block/commit.c index c4a98e5804..7a6ae59d42 100644 --- a/block/commit.c +++ b/block/commit.c @@ -282,7 +282,7 @@ void commit_start(const char *job_id, BlockDriverState = *bs, } =20 s =3D block_job_create(job_id, &commit_job_driver, NULL, bs, 0, BLK_PE= RM_ALL, - speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp); + speed, JOB_DEFAULT, NULL, NULL, errp); if (!s) { return; } diff --git a/block/mirror.c b/block/mirror.c index 876b636121..fc3bd702dc 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1278,7 +1278,7 @@ void mirror_start(const char *job_id, BlockDriverStat= e *bs, } is_none_mode =3D mode =3D=3D MIRROR_SYNC_MODE_NONE; base =3D mode =3D=3D MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL; - mirror_start_job(job_id, bs, BLOCK_JOB_DEFAULT, target, replaces, + mirror_start_job(job_id, bs, JOB_DEFAULT, target, replaces, speed, granularity, buf_size, backing_mode, on_source_error, on_target_error, unmap, NULL, NULL, &mirror_job_driver, is_none_mode, base, false, diff --git a/block/replication.c b/block/replication.c index 3f7500ee3f..8241400155 100644 --- a/block/replication.c +++ b/block/replication.c @@ -566,7 +566,7 @@ static void replication_start(ReplicationState *rs, Rep= licationMode mode, job =3D backup_job_create(NULL, s->secondary_disk->bs, s->hidden_d= isk->bs, 0, MIRROR_SYNC_MODE_NONE, NULL, false, BLOCKDEV_ON_ERROR_REPORT, - BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERN= AL, + BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL, backup_job_completed, bs, NULL, &local_err= ); if (local_err) { error_propagate(errp, local_err); @@ -691,7 +691,7 @@ static void replication_stop(ReplicationState *rs, bool= failover, Error **errp) =20 s->stage =3D BLOCK_REPLICATION_FAILOVER; commit_active_start(NULL, s->active_disk->bs, s->secondary_disk->b= s, - BLOCK_JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPOR= T, + JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT, NULL, replication_done, bs, true, errp); break; default: diff --git a/block/stream.c b/block/stream.c index e81b488a22..eee02538ed 100644 --- a/block/stream.c +++ b/block/stream.c @@ -242,7 +242,7 @@ void stream_start(const char *job_id, BlockDriverState = *bs, BLK_PERM_GRAPH_MOD, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANG= ED | BLK_PERM_WRITE, - speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp); + speed, JOB_DEFAULT, NULL, NULL, errp); if (!s) { goto fail; } diff --git a/blockdev.c b/blockdev.c index 891cbe9940..fb7a3142e7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3244,7 +3244,7 @@ void qmp_block_commit(bool has_job_id, const char *jo= b_id, const char *device, goto out; } commit_active_start(has_job_id ? job_id : NULL, bs, base_bs, - BLOCK_JOB_DEFAULT, speed, on_error, + JOB_DEFAULT, speed, on_error, filter_node_name, NULL, NULL, false, &local_er= r); } else { BlockDriverState *overlay_bs =3D bdrv_find_overlay(bs, top_bs); @@ -3275,7 +3275,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup,= BlockJobTxn *txn, AioContext *aio_context; QDict *options =3D NULL; Error *local_err =3D NULL; - int flags, job_flags =3D BLOCK_JOB_DEFAULT; + int flags, job_flags =3D JOB_DEFAULT; int64_t size; bool set_backing_hd =3D false; =20 @@ -3398,10 +3398,10 @@ static BlockJob *do_drive_backup(DriveBackup *backu= p, BlockJobTxn *txn, } } if (!backup->auto_finalize) { - job_flags |=3D BLOCK_JOB_MANUAL_FINALIZE; + job_flags |=3D JOB_MANUAL_FINALIZE; } if (!backup->auto_dismiss) { - job_flags |=3D BLOCK_JOB_MANUAL_DISMISS; + job_flags |=3D JOB_MANUAL_DISMISS; } =20 job =3D backup_job_create(backup->job_id, bs, target_bs, backup->speed, @@ -3442,7 +3442,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, = BlockJobTxn *txn, Error *local_err =3D NULL; AioContext *aio_context; BlockJob *job =3D NULL; - int job_flags =3D BLOCK_JOB_DEFAULT; + int job_flags =3D JOB_DEFAULT; =20 if (!backup->has_speed) { backup->speed =3D 0; @@ -3491,10 +3491,10 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup= , BlockJobTxn *txn, } } if (!backup->auto_finalize) { - job_flags |=3D BLOCK_JOB_MANUAL_FINALIZE; + job_flags |=3D JOB_MANUAL_FINALIZE; } if (!backup->auto_dismiss) { - job_flags |=3D BLOCK_JOB_MANUAL_DISMISS; + job_flags |=3D JOB_MANUAL_DISMISS; } job =3D backup_job_create(backup->job_id, bs, target_bs, backup->speed, backup->sync, NULL, backup->compress, diff --git a/blockjob.c b/blockjob.c index 54e74c5a76..62f4a87744 100644 --- a/blockjob.c +++ b/blockjob.c @@ -286,7 +286,7 @@ static void block_job_do_dismiss(BlockJob *job) static void block_job_conclude(BlockJob *job) { job_state_transition(&job->job, JOB_STATUS_CONCLUDED); - if (job->auto_dismiss || !job_started(&job->job)) { + if (job->job.auto_dismiss || !job_started(&job->job)) { block_job_do_dismiss(job); } } @@ -484,7 +484,7 @@ static void block_job_completed_txn_abort(BlockJob *job) =20 static int block_job_needs_finalize(BlockJob *job) { - return !job->auto_finalize; + return !job->job.auto_finalize; } =20 static void block_job_do_finalize(BlockJob *job) @@ -689,8 +689,8 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **er= rp) info->io_status =3D job->iostatus; info->ready =3D job->ready; info->status =3D job->job.status; - info->auto_finalize =3D job->auto_finalize; - info->auto_dismiss =3D job->auto_dismiss; + info->auto_finalize =3D job->job.auto_finalize; + info->auto_dismiss =3D job->job.auto_dismiss; return info; } =20 @@ -735,7 +735,7 @@ static void block_job_event_completed(BlockJob *job, co= nst char *msg) static int block_job_event_pending(BlockJob *job) { job_state_transition(&job->job, JOB_STATUS_PENDING); - if (!job->auto_finalize && !block_job_is_internal(job)) { + if (!job->job.auto_finalize && !block_job_is_internal(job)) { qapi_event_send_block_job_pending(job_type(&job->job), job->job.id, &error_abort); @@ -762,19 +762,8 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, return NULL; } =20 - if (job_id =3D=3D NULL && !(flags & BLOCK_JOB_INTERNAL)) { + if (job_id =3D=3D NULL && !(flags & JOB_INTERNAL)) { job_id =3D bdrv_get_device_name(bs); - if (!*job_id) { - error_setg(errp, "An explicit job ID is required for this node= "); - return NULL; - } - } - - if (job_id) { - if (flags & BLOCK_JOB_INTERNAL) { - error_setg(errp, "Cannot specify job ID for internal block job= "); - return NULL; - } } =20 blk =3D blk_new(perm, shared_perm); @@ -785,7 +774,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, } =20 job =3D job_create(job_id, &driver->job_driver, blk_get_aio_context(bl= k), - errp); + flags, errp); if (job =3D=3D NULL) { blk_unref(blk); return NULL; @@ -799,8 +788,6 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, job->blk =3D blk; job->cb =3D cb; job->opaque =3D opaque; - job->auto_finalize =3D !(flags & BLOCK_JOB_MANUAL_FINALIZE); - job->auto_dismiss =3D !(flags & BLOCK_JOB_MANUAL_DISMISS); =20 error_setg(&job->blocker, "block device is in use by block job: %s", job_type_str(&job->job)); diff --git a/job.c b/job.c index 92157e59ea..98113196af 100644 --- a/job.c +++ b/job.c @@ -183,11 +183,15 @@ static void job_sleep_timer_cb(void *opaque) } =20 void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, - Error **errp) + int flags, Error **errp) { Job *job; =20 if (job_id) { + if (flags & JOB_INTERNAL) { + error_setg(errp, "Cannot specify job ID for internal job"); + return NULL; + } if (!id_wellformed(job_id)) { error_setg(errp, "Invalid job ID '%s'", job_id); return NULL; @@ -196,6 +200,9 @@ void *job_create(const char *job_id, const JobDriver *d= river, AioContext *ctx, error_setg(errp, "Job ID '%s' already in use", job_id); return NULL; } + } else if (!(flags & JOB_INTERNAL)) { + error_setg(errp, "An explicit job ID is required"); + return NULL; } =20 job =3D g_malloc0(driver->instance_size); @@ -206,6 +213,8 @@ void *job_create(const char *job_id, const JobDriver *d= river, AioContext *ctx, job->busy =3D false; job->paused =3D true; job->pause_count =3D 1; + job->auto_finalize =3D !(flags & JOB_MANUAL_FINALIZE); + job->auto_dismiss =3D !(flags & JOB_MANUAL_DISMISS); =20 job_state_transition(job, JOB_STATUS_CREATED); aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, diff --git a/qemu-img.c b/qemu-img.c index 081b03fd91..3db8c557b4 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1015,7 +1015,7 @@ static int img_commit(int argc, char **argv) =20 aio_context =3D bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - commit_active_start("commit", bs, base_bs, BLOCK_JOB_DEFAULT, 0, + commit_active_start("commit", bs, base_bs, JOB_DEFAULT, 0, BLOCKDEV_ON_ERROR_REPORT, NULL, common_block_job_c= b, &cbi, false, &local_err); aio_context_release(aio_context); diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 93d1ff0859..60e9fa2298 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -107,7 +107,7 @@ static BlockJob *test_block_job_start(unsigned int iter= ations, =20 snprintf(job_id, sizeof(job_id), "job%u", counter++); s =3D block_job_create(job_id, &test_block_job_driver, txn, bs, - 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, + 0, BLK_PERM_ALL, 0, JOB_DEFAULT, test_block_job_cb, data, &error_abort); s->iterations =3D iterations; s->use_timer =3D use_timer; diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index ceb59600ed..8bb0aa8f85 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -59,7 +59,7 @@ static BlockJob *do_test_id(BlockBackend *blk, const char= *id, bool should_succeed) { return mk_job(blk, id, &test_block_job_driver, - should_succeed, BLOCK_JOB_DEFAULT); + should_succeed, JOB_DEFAULT); } =20 /* This creates a BlockBackend (optionally with a name) with a @@ -214,7 +214,7 @@ static CancelJob *create_common(BlockJob **pjob) =20 blk =3D create_blk(NULL); job =3D mk_job(blk, "Steve", &test_cancel_driver, true, - BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); + JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); job_ref(&job->job); assert(job->job.status =3D=3D JOB_STATUS_CREATED); s =3D container_of(job, CancelJob, common); --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585465194506.1679281779901; Tue, 24 Apr 2018 08:57:45 -0700 (PDT) Received: from localhost ([::1]:59278 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0K3-0008BX-9B for importer@patchew.org; Tue, 24 Apr 2018 11:57:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47996) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpM-00089j-S3 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpL-0008LD-Sa for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:56 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34858 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpI-0008GC-Gu; Tue, 24 Apr 2018 11:25:52 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1B145FE5CA; Tue, 24 Apr 2018 15:25:52 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0AF332026990; Tue, 24 Apr 2018 15:25:50 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:04 +0200 Message-Id: <20180424152515.25664-23-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:52 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:52 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 22/33] blockjob: Split block_job_event_pending() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" block_job_event_pending() doesn't only send a QMP event, but it also transitions to the PENDING state. Split the function so that we get one part only sending the event (like other block_job_event_* functions) and another part than does the state transition. Signed-off-by: Kevin Wolf --- blockjob.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/blockjob.c b/blockjob.c index 62f4a87744..c49cfdf130 100644 --- a/blockjob.c +++ b/blockjob.c @@ -38,7 +38,7 @@ =20 static void block_job_event_cancelled(BlockJob *job); static void block_job_event_completed(BlockJob *job, const char *msg); -static int block_job_event_pending(BlockJob *job); +static void block_job_event_pending(BlockJob *job); =20 /* Transactional group of block jobs */ struct BlockJobTxn { @@ -501,6 +501,15 @@ static void block_job_do_finalize(BlockJob *job) } } =20 +static int block_job_transition_to_pending(BlockJob *job) +{ + job_state_transition(&job->job, JOB_STATUS_PENDING); + if (!job->job.auto_finalize) { + block_job_event_pending(job); + } + return 0; +} + static void block_job_completed_txn_success(BlockJob *job) { BlockJobTxn *txn =3D job->txn; @@ -519,7 +528,7 @@ static void block_job_completed_txn_success(BlockJob *j= ob) assert(other_job->ret =3D=3D 0); } =20 - block_job_txn_apply(txn, block_job_event_pending, false); + block_job_txn_apply(txn, block_job_transition_to_pending, false); =20 /* If no jobs need manual finalization, automatically do so */ if (block_job_txn_apply(txn, block_job_needs_finalize, false) =3D=3D 0= ) { @@ -732,15 +741,15 @@ static void block_job_event_completed(BlockJob *job, = const char *msg) &error_abort); } =20 -static int block_job_event_pending(BlockJob *job) +static void block_job_event_pending(BlockJob *job) { - job_state_transition(&job->job, JOB_STATUS_PENDING); - if (!job->job.auto_finalize && !block_job_is_internal(job)) { - qapi_event_send_block_job_pending(job_type(&job->job), - job->job.id, - &error_abort); + if (block_job_is_internal(job)) { + return; } - return 0; + + qapi_event_send_block_job_pending(job_type(&job->job), + job->job.id, + &error_abort); } =20 /* --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584414346366.0900840038664; Tue, 24 Apr 2018 08:40:14 -0700 (PDT) Received: from localhost ([::1]:59159 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB03B-0002HQ-Ez for importer@patchew.org; Tue, 24 Apr 2018 11:40:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48046) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpO-0008Bt-IZ for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpM-0008MD-VM for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:25:58 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45632 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpJ-0008Iv-QE; Tue, 24 Apr 2018 11:25:53 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6747D4270969; Tue, 24 Apr 2018 15:25:53 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5720F2026990; Tue, 24 Apr 2018 15:25:52 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:05 +0200 Message-Id: <20180424152515.25664-24-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:25:53 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:25:53 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 23/33] job: Add job_event_*() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Go through the Job layer in order to send QMP events. For the moment, these functions only call a notifier in the BlockJob layer that sends the existing commands. This uses notifiers rather than JobDriver callbacks because internal users of jobs won't receive QMP events, but might still be interested in getting notified for the events. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 9 +++++++++ include/qemu/job.h | 18 ++++++++++++++++++ blockjob.c | 42 ++++++++++++++++++++++++++++-------------- job.c | 19 +++++++++++++++++++ 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index a74d5d02fd..b5bcb52219 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -82,6 +82,15 @@ typedef struct BlockJob { /** Block other operations when block job is running */ Error *blocker; =20 + /** Called when a cancelled job is finalised. */ + Notifier finalize_cancelled_notifier; + + /** Called when a successfully completed job is finalised. */ + Notifier finalize_completed_notifier; + + /** Called when the job transitions to PENDING */ + Notifier pending_notifier; + /** BlockDriverStates that are involved in this block job */ GSList *nodes; =20 diff --git a/include/qemu/job.h b/include/qemu/job.h index ab3d49685a..3d9a9a8d77 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -105,6 +105,15 @@ typedef struct Job { /** True if this job should automatically dismiss itself */ bool auto_dismiss; =20 + /** Notifiers called when a cancelled job is finalised */ + NotifierList on_finalize_cancelled; + + /** Notifiers called when a successfully completed job is finalised */ + NotifierList on_finalize_completed; + + /** Notifiers called when the job transitions to PENDING */ + NotifierList on_pending; + /** Element of the list of jobs */ QLIST_ENTRY(Job) job_list; } Job; @@ -182,6 +191,15 @@ void job_ref(Job *job); */ void job_unref(Job *job); =20 +/** To be called when a cancelled job is finalised. */ +void job_event_cancelled(Job *job); + +/** To be called when a successfully completed job is finalised. */ +void job_event_completed(Job *job); + +/** To be called when the job transitions to PENDING */ +void job_event_pending(Job *job); + /** * @job: A job that has not yet been started. * diff --git a/blockjob.c b/blockjob.c index c49cfdf130..2f36888c0a 100644 --- a/blockjob.c +++ b/blockjob.c @@ -36,10 +36,6 @@ #include "qemu/coroutine.h" #include "qemu/timer.h" =20 -static void block_job_event_cancelled(BlockJob *job); -static void block_job_event_completed(BlockJob *job, const char *msg); -static void block_job_event_pending(BlockJob *job); - /* Transactional group of block jobs */ struct BlockJobTxn { =20 @@ -353,13 +349,9 @@ static int block_job_finalize_single(BlockJob *job) /* Emit events only if we actually started */ if (job_started(&job->job)) { if (job_is_cancelled(&job->job)) { - block_job_event_cancelled(job); + job_event_cancelled(&job->job); } else { - const char *msg =3D NULL; - if (job->ret < 0) { - msg =3D strerror(-job->ret); - } - block_job_event_completed(job, msg); + job_event_completed(&job->job); } } =20 @@ -505,7 +497,7 @@ static int block_job_transition_to_pending(BlockJob *jo= b) { job_state_transition(&job->job, JOB_STATUS_PENDING); if (!job->job.auto_finalize) { - block_job_event_pending(job); + job_event_pending(&job->job); } return 0; } @@ -711,8 +703,10 @@ static void block_job_iostatus_set_err(BlockJob *job, = int error) } } =20 -static void block_job_event_cancelled(BlockJob *job) +static void block_job_event_cancelled(Notifier *n, void *opaque) { + BlockJob *job =3D opaque; + if (block_job_is_internal(job)) { return; } @@ -725,12 +719,19 @@ static void block_job_event_cancelled(BlockJob *job) &error_abort); } =20 -static void block_job_event_completed(BlockJob *job, const char *msg) +static void block_job_event_completed(Notifier *n, void *opaque) { + BlockJob *job =3D opaque; + const char *msg =3D NULL; + if (block_job_is_internal(job)) { return; } =20 + if (job->ret < 0) { + msg =3D strerror(-job->ret); + } + qapi_event_send_block_job_completed(job_type(&job->job), job->job.id, job->len, @@ -741,8 +742,10 @@ static void block_job_event_completed(BlockJob *job, c= onst char *msg) &error_abort); } =20 -static void block_job_event_pending(BlockJob *job) +static void block_job_event_pending(Notifier *n, void *opaque) { + BlockJob *job =3D opaque; + if (block_job_is_internal(job)) { return; } @@ -798,6 +801,17 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, job->cb =3D cb; job->opaque =3D opaque; =20 + job->finalize_cancelled_notifier.notify =3D block_job_event_cancelled; + job->finalize_completed_notifier.notify =3D block_job_event_completed; + job->pending_notifier.notify =3D block_job_event_pending; + + notifier_list_add(&job->job.on_finalize_cancelled, + &job->finalize_cancelled_notifier); + notifier_list_add(&job->job.on_finalize_completed, + &job->finalize_completed_notifier); + notifier_list_add(&job->job.on_pending, + &job->pending_notifier); + error_setg(&job->blocker, "block device is in use by block job: %s", job_type_str(&job->job)); block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort= ); diff --git a/job.c b/job.c index 98113196af..ab9d6d8a22 100644 --- a/job.c +++ b/job.c @@ -216,6 +216,10 @@ void *job_create(const char *job_id, const JobDriver *= driver, AioContext *ctx, job->auto_finalize =3D !(flags & JOB_MANUAL_FINALIZE); job->auto_dismiss =3D !(flags & JOB_MANUAL_DISMISS); =20 + notifier_list_init(&job->on_finalize_cancelled); + notifier_list_init(&job->on_finalize_completed); + notifier_list_init(&job->on_pending); + job_state_transition(job, JOB_STATUS_CREATED); aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, QEMU_CLOCK_REALTIME, SCALE_NS, @@ -248,6 +252,21 @@ void job_unref(Job *job) } } =20 +void job_event_cancelled(Job *job) +{ + notifier_list_notify(&job->on_finalize_cancelled, job); +} + +void job_event_completed(Job *job) +{ + notifier_list_notify(&job->on_finalize_completed, job); +} + +void job_event_pending(Job *job) +{ + notifier_list_notify(&job->on_pending, job); +} + /* * Conditionally enter a job pending a call to fn() while under the job_lo= ck * critical section. --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585808850729.1845341897458; Tue, 24 Apr 2018 09:03:28 -0700 (PDT) Received: from localhost ([::1]:59322 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Pb-0004Um-Pn for importer@patchew.org; Tue, 24 Apr 2018 12:03:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48140) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpT-0008JE-PY for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpR-0008TJ-5d for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:03 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34862 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpL-0008KU-3H; Tue, 24 Apr 2018 11:25:55 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B3A35FB674; Tue, 24 Apr 2018 15:25:54 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id A2AB4202342F; Tue, 24 Apr 2018 15:25:53 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:06 +0200 Message-Id: <20180424152515.25664-25-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:54 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:54 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 24/33] job: Move single job finalisation to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves the finalisation of a single job from BlockJob to Job. Some part of this code depends on job transactions, and job transactions call this code, we introduce some temporary calls from Job functions to BlockJob ones. This will be fixed once transactions move to Job, too. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 9 --- include/block/blockjob_int.h | 36 ----------- include/qemu/job.h | 53 ++++++++++++++++- block/backup.c | 22 +++---- block/commit.c | 2 +- block/mirror.c | 2 +- blockjob.c | 138 ++++++++-------------------------------= ---- job.c | 101 ++++++++++++++++++++++++++++++- qemu-img.c | 2 +- tests/test-blockjob.c | 10 ++-- 10 files changed, 194 insertions(+), 181 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index b5bcb52219..e5af02f751 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -76,9 +76,6 @@ typedef struct BlockJob { /** Rate limiting data structure for implementing @speed. */ RateLimit limit; =20 - /** The completion function that will be called when the job completes= . */ - BlockCompletionFunc *cb; - /** Block other operations when block job is running */ Error *blocker; =20 @@ -94,12 +91,6 @@ typedef struct BlockJob { /** BlockDriverStates that are involved in this block job */ GSList *nodes; =20 - /** The opaque value that is passed to the completion function. */ - void *opaque; - - /** ret code passed to block_job_completed. */ - int ret; - BlockJobTxn *txn; QLIST_ENTRY(BlockJob) txn_list; } BlockJob; diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 543ca556fc..5b0a905c76 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -54,34 +54,6 @@ struct BlockJobDriver { */ int (*prepare)(BlockJob *job); =20 - /** - * If the callback is not NULL, it will be invoked when all the jobs - * belonging to the same transaction complete; or upon this job's - * completion if it is not in a transaction. Skipped if NULL. - * - * All jobs will complete with a call to either .commit() or .abort() = but - * never both. - */ - void (*commit)(BlockJob *job); - - /** - * If the callback is not NULL, it will be invoked when any job in the - * same transaction fails; or upon this job's failure (due to error or - * cancellation) if it is not in a transaction. Skipped if NULL. - * - * All jobs will complete with a call to either .commit() or .abort() = but - * never both. - */ - void (*abort)(BlockJob *job); - - /** - * If the callback is not NULL, it will be invoked after a call to eit= her - * .commit() or .abort(). Regardless of which callback is invoked after - * completion, .clean() will always be called, even if the job does not - * belong to a transaction group. - */ - void (*clean)(BlockJob *job); - /* * If the callback is not NULL, it will be invoked before the job is * resumed in a new AioContext. This is the place to move any resourc= es @@ -156,14 +128,6 @@ void block_job_yield(BlockJob *job); int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n); =20 /** - * block_job_early_fail: - * @bs: The block device. - * - * The block job could not be started, free it. - */ -void block_job_early_fail(BlockJob *job); - -/** * block_job_completed: * @job: The job being completed. * @ret: The status code. diff --git a/include/qemu/job.h b/include/qemu/job.h index 3d9a9a8d77..f456e4f27d 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -29,6 +29,7 @@ #include "qapi/qapi-types-block-core.h" #include "qemu/queue.h" #include "qemu/coroutine.h" +#include "block/aio.h" =20 typedef struct JobDriver JobDriver; =20 @@ -105,6 +106,15 @@ typedef struct Job { /** True if this job should automatically dismiss itself */ bool auto_dismiss; =20 + /** ret code passed to block_job_completed. */ + int ret; + + /** The completion function that will be called when the job completes= . */ + BlockCompletionFunc *cb; + + /** The opaque value that is passed to the completion function. */ + void *opaque; + /** Notifiers called when a cancelled job is finalised */ NotifierList on_finalize_cancelled; =20 @@ -151,6 +161,35 @@ struct JobDriver { */ void (*user_resume)(Job *job); =20 + /** + * If the callback is not NULL, it will be invoked when all the jobs + * belonging to the same transaction complete; or upon this job's + * completion if it is not in a transaction. Skipped if NULL. + * + * All jobs will complete with a call to either .commit() or .abort() = but + * never both. + */ + void (*commit)(Job *job); + + /** + * If the callback is not NULL, it will be invoked when any job in the + * same transaction fails; or upon this job's failure (due to error or + * cancellation) if it is not in a transaction. Skipped if NULL. + * + * All jobs will complete with a call to either .commit() or .abort() = but + * never both. + */ + void (*abort)(Job *job); + + /** + * If the callback is not NULL, it will be invoked after a call to eit= her + * .commit() or .abort(). Regardless of which callback is invoked after + * completion, .clean() will always be called, even if the job does not + * belong to a transaction group. + */ + void (*clean)(Job *job); + + /** Called when the job is freed */ void (*free)(Job *job); }; @@ -174,10 +213,12 @@ typedef enum JobCreateFlags { * @driver: The class object for the newly-created job. * @ctx: The AioContext to run the job coroutine in. * @flags: Creation flags for the job. See @JobCreateFlags. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. * @errp: Error object. */ void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, - int flags, Error **errp); + int flags, BlockCompletionFunc *cb, void *opaque, Error *= *errp); =20 /** * Add a reference to Job refcnt, it will be decreased with job_unref, and= then @@ -276,6 +317,10 @@ Job *job_next(Job *job); */ Job *job_get(const char *id); =20 +/** The @job could not be started, free it. */ +void job_early_fail(Job *job); + + typedef void JobDeferToMainLoopFn(Job *job, void *opaque); =20 /** @@ -302,5 +347,11 @@ bool job_started(Job *job); void job_enter_cond(Job *job, bool(*fn)(Job *job)); void job_pause(Job *job); void job_resume(Job *job); +void job_do_dismiss(Job *job); +int job_finalize_single(Job *job); +void job_update_rc(Job *job); + +typedef struct BlockJob BlockJob; +void block_job_txn_del_job(BlockJob *job); =20 #endif diff --git a/block/backup.c b/block/backup.c index eca4f764c4..1f17025505 100644 --- a/block/backup.c +++ b/block/backup.c @@ -207,25 +207,25 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob= *job, int ret) } } =20 -static void backup_commit(BlockJob *job) +static void backup_commit(Job *job) { - BackupBlockJob *s =3D container_of(job, BackupBlockJob, common); + BackupBlockJob *s =3D container_of(job, BackupBlockJob, common.job); if (s->sync_bitmap) { backup_cleanup_sync_bitmap(s, 0); } } =20 -static void backup_abort(BlockJob *job) +static void backup_abort(Job *job) { - BackupBlockJob *s =3D container_of(job, BackupBlockJob, common); + BackupBlockJob *s =3D container_of(job, BackupBlockJob, common.job); if (s->sync_bitmap) { backup_cleanup_sync_bitmap(s, -1); } } =20 -static void backup_clean(BlockJob *job) +static void backup_clean(Job *job) { - BackupBlockJob *s =3D container_of(job, BackupBlockJob, common); + BackupBlockJob *s =3D container_of(job, BackupBlockJob, common.job); assert(s->target); blk_unref(s->target); s->target =3D NULL; @@ -530,10 +530,10 @@ static const BlockJobDriver backup_job_driver =3D { .free =3D block_job_free, .user_resume =3D block_job_user_resume, .start =3D backup_run, + .commit =3D backup_commit, + .abort =3D backup_abort, + .clean =3D backup_clean, }, - .commit =3D backup_commit, - .abort =3D backup_abort, - .clean =3D backup_clean, .attached_aio_context =3D backup_attached_aio_context, .drain =3D backup_drain, }; @@ -678,8 +678,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDr= iverState *bs, bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL); } if (job) { - backup_clean(&job->common); - block_job_early_fail(&job->common); + backup_clean(&job->common.job); + job_early_fail(&job->common.job); } =20 return NULL; diff --git a/block/commit.c b/block/commit.c index 7a6ae59d42..e53b2d7d55 100644 --- a/block/commit.c +++ b/block/commit.c @@ -385,7 +385,7 @@ fail: if (commit_top_bs) { bdrv_replace_node(commit_top_bs, top, &error_abort); } - block_job_early_fail(&s->common); + job_early_fail(&s->common.job); } =20 =20 diff --git a/block/mirror.c b/block/mirror.c index fc3bd702dc..3266553ffb 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1251,7 +1251,7 @@ fail: =20 g_free(s->replaces); blk_unref(s->target); - block_job_early_fail(&s->common); + job_early_fail(&s->common.job); } =20 bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL, diff --git a/blockjob.c b/blockjob.c index 2f36888c0a..677938a3b7 100644 --- a/blockjob.c +++ b/blockjob.c @@ -128,7 +128,7 @@ void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *= job) block_job_txn_ref(txn); } =20 -static void block_job_txn_del_job(BlockJob *job) +void block_job_txn_del_job(BlockJob *job) { if (job->txn) { QLIST_REMOVE(job, txn_list); @@ -263,101 +263,12 @@ const BlockJobDriver *block_job_driver(BlockJob *job) return job->driver; } =20 -static void block_job_decommission(BlockJob *job) -{ - assert(job); - job->job.busy =3D false; - job->job.paused =3D false; - job->job.deferred_to_main_loop =3D true; - block_job_txn_del_job(job); - job_state_transition(&job->job, JOB_STATUS_NULL); - job_unref(&job->job); -} - -static void block_job_do_dismiss(BlockJob *job) -{ - block_job_decommission(job); -} - -static void block_job_conclude(BlockJob *job) -{ - job_state_transition(&job->job, JOB_STATUS_CONCLUDED); - if (job->job.auto_dismiss || !job_started(&job->job)) { - block_job_do_dismiss(job); - } -} - -static void block_job_update_rc(BlockJob *job) -{ - if (!job->ret && job_is_cancelled(&job->job)) { - job->ret =3D -ECANCELED; - } - if (job->ret) { - job_state_transition(&job->job, JOB_STATUS_ABORTING); - } -} - static int block_job_prepare(BlockJob *job) { - if (job->ret =3D=3D 0 && job->driver->prepare) { - job->ret =3D job->driver->prepare(job); - } - return job->ret; -} - -static void block_job_commit(BlockJob *job) -{ - assert(!job->ret); - if (job->driver->commit) { - job->driver->commit(job); - } -} - -static void block_job_abort(BlockJob *job) -{ - assert(job->ret); - if (job->driver->abort) { - job->driver->abort(job); - } -} - -static void block_job_clean(BlockJob *job) -{ - if (job->driver->clean) { - job->driver->clean(job); + if (job->job.ret =3D=3D 0 && job->driver->prepare) { + job->job.ret =3D job->driver->prepare(job); } -} - -static int block_job_finalize_single(BlockJob *job) -{ - assert(job_is_completed(&job->job)); - - /* Ensure abort is called for late-transactional failures */ - block_job_update_rc(job); - - if (!job->ret) { - block_job_commit(job); - } else { - block_job_abort(job); - } - block_job_clean(job); - - if (job->cb) { - job->cb(job->opaque, job->ret); - } - - /* Emit events only if we actually started */ - if (job_started(&job->job)) { - if (job_is_cancelled(&job->job)) { - job_event_cancelled(&job->job); - } else { - job_event_completed(&job->job); - } - } - - block_job_txn_del_job(job); - block_job_conclude(job); - return 0; + return job->job.ret; } =20 static void block_job_cancel_async(BlockJob *job, bool force) @@ -425,8 +336,8 @@ static int block_job_finish_sync(BlockJob *job, while (!job_is_completed(&job->job)) { aio_poll(qemu_get_aio_context(), true); } - ret =3D (job_is_cancelled(&job->job) && job->ret =3D=3D 0) - ? -ECANCELED : job->ret; + ret =3D (job_is_cancelled(&job->job) && job->job.ret =3D=3D 0) + ? -ECANCELED : job->job.ret; job_unref(&job->job); return ret; } @@ -467,7 +378,7 @@ static void block_job_completed_txn_abort(BlockJob *job) assert(job_is_cancelled(&other_job->job)); block_job_finish_sync(other_job, NULL, NULL); } - block_job_finalize_single(other_job); + job_finalize_single(&other_job->job); aio_context_release(ctx); } =20 @@ -479,6 +390,11 @@ static int block_job_needs_finalize(BlockJob *job) return !job->job.auto_finalize; } =20 +static int block_job_finalize_single(BlockJob *job) +{ + return job_finalize_single(&job->job); +} + static void block_job_do_finalize(BlockJob *job) { int rc; @@ -517,7 +433,7 @@ static void block_job_completed_txn_success(BlockJob *j= ob) if (!job_is_completed(&other_job->job)) { return; } - assert(other_job->ret =3D=3D 0); + assert(other_job->job.ret =3D=3D 0); } =20 block_job_txn_apply(txn, block_job_transition_to_pending, false); @@ -602,14 +518,14 @@ void block_job_dismiss(BlockJob **jobptr, Error **err= p) return; } =20 - block_job_do_dismiss(job); + job_do_dismiss(&job->job); *jobptr =3D NULL; } =20 void block_job_cancel(BlockJob *job, bool force) { if (job->job.status =3D=3D JOB_STATUS_CONCLUDED) { - block_job_do_dismiss(job); + job_do_dismiss(&job->job); return; } block_job_cancel_async(job, force); @@ -728,8 +644,8 @@ static void block_job_event_completed(Notifier *n, void= *opaque) return; } =20 - if (job->ret < 0) { - msg =3D strerror(-job->ret); + if (job->job.ret < 0) { + msg =3D strerror(-job->job.ret); } =20 qapi_event_send_block_job_completed(job_type(&job->job), @@ -786,7 +702,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, } =20 job =3D job_create(job_id, &driver->job_driver, blk_get_aio_context(bl= k), - flags, errp); + flags, cb, opaque, errp); if (job =3D=3D NULL) { blk_unref(blk); return NULL; @@ -798,8 +714,6 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, =20 job->driver =3D driver; job->blk =3D blk; - job->cb =3D cb; - job->opaque =3D opaque; =20 job->finalize_cancelled_notifier.notify =3D block_job_event_cancelled; job->finalize_completed_notifier.notify =3D block_job_event_completed; @@ -828,7 +742,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, =20 block_job_set_speed(job, speed, &local_err); if (local_err) { - block_job_early_fail(job); + job_early_fail(&job->job); error_propagate(errp, local_err); return NULL; } @@ -847,20 +761,14 @@ void *block_job_create(const char *job_id, const Bloc= kJobDriver *driver, return job; } =20 -void block_job_early_fail(BlockJob *job) -{ - assert(job->job.status =3D=3D JOB_STATUS_CREATED); - block_job_decommission(job); -} - void block_job_completed(BlockJob *job, int ret) { assert(job && job->txn && !job_is_completed(&job->job)); assert(blk_bs(job->blk)->job =3D=3D job); - job->ret =3D ret; - block_job_update_rc(job); - trace_block_job_completed(job, ret, job->ret); - if (job->ret) { + job->job.ret =3D ret; + job_update_rc(&job->job); + trace_block_job_completed(job, ret, job->job.ret); + if (job->job.ret) { block_job_completed_txn_abort(job); } else { block_job_completed_txn_success(job); diff --git a/job.c b/job.c index ab9d6d8a22..0ad8f29982 100644 --- a/job.c +++ b/job.c @@ -31,6 +31,9 @@ #include "qemu/main-loop.h" #include "trace-root.h" =20 +/* TODO Remove again once the direct calls back to blockjob_* are gone */ +#include "block/blockjob_int.h" + static QLIST_HEAD(, Job) jobs =3D QLIST_HEAD_INITIALIZER(jobs); =20 /* Job State Transition Table */ @@ -183,7 +186,7 @@ static void job_sleep_timer_cb(void *opaque) } =20 void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, - int flags, Error **errp) + int flags, BlockCompletionFunc *cb, void *opaque, Error *= *errp) { Job *job; =20 @@ -215,6 +218,8 @@ void *job_create(const char *job_id, const JobDriver *d= river, AioContext *ctx, job->pause_count =3D 1; job->auto_finalize =3D !(flags & JOB_MANUAL_FINALIZE); job->auto_dismiss =3D !(flags & JOB_MANUAL_DISMISS); + job->cb =3D cb; + job->opaque =3D opaque; =20 notifier_list_init(&job->on_finalize_cancelled); notifier_list_init(&job->on_finalize_completed); @@ -446,6 +451,100 @@ void job_user_resume(Job *job, Error **errp) job_resume(job); } =20 +void job_do_dismiss(Job *job) +{ + assert(job); + job->busy =3D false; + job->paused =3D false; + job->deferred_to_main_loop =3D true; + + /* TODO Don't assume it's a BlockJob */ + block_job_txn_del_job((BlockJob*) job); + + job_state_transition(job, JOB_STATUS_NULL); + job_unref(job); +} + +void job_early_fail(Job *job) +{ + assert(job->status =3D=3D JOB_STATUS_CREATED); + job_do_dismiss(job); +} + +static void job_conclude(Job *job) +{ + job_state_transition(job, JOB_STATUS_CONCLUDED); + if (job->auto_dismiss || !job_started(job)) { + job_do_dismiss(job); + } +} + +void job_update_rc(Job *job) +{ + if (!job->ret && job_is_cancelled(job)) { + job->ret =3D -ECANCELED; + } + if (job->ret) { + job_state_transition(job, JOB_STATUS_ABORTING); + } +} + +static void job_commit(Job *job) +{ + assert(!job->ret); + if (job->driver->commit) { + job->driver->commit(job); + } +} + +static void job_abort(Job *job) +{ + assert(job->ret); + if (job->driver->abort) { + job->driver->abort(job); + } +} + +static void job_clean(Job *job) +{ + if (job->driver->clean) { + job->driver->clean(job); + } +} + +int job_finalize_single(Job *job) +{ + assert(job_is_completed(job)); + + /* Ensure abort is called for late-transactional failures */ + job_update_rc(job); + + if (!job->ret) { + job_commit(job); + } else { + job_abort(job); + } + job_clean(job); + + if (job->cb) { + job->cb(job->opaque, job->ret); + } + + /* Emit events only if we actually started */ + if (job_started(job)) { + if (job_is_cancelled(job)) { + job_event_cancelled(job); + } else { + job_event_completed(job); + } + } + + /* TODO Don't assume it's a BlockJob */ + block_job_txn_del_job((BlockJob*) job); + job_conclude(job); + return 0; +} + =20 typedef struct { Job *job; diff --git a/qemu-img.c b/qemu-img.c index 3db8c557b4..4888064beb 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -872,7 +872,7 @@ static void run_block_job(BlockJob *job, Error **errp) if (!job_is_completed(&job->job)) { ret =3D block_job_complete_sync(job, errp); } else { - ret =3D job->ret; + ret =3D job->job.ret; } job_unref(&job->job); aio_context_release(aio_context); diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 8bb0aa8f85..1fe6803fe0 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -128,11 +128,11 @@ static void test_job_ids(void) job[1] =3D do_test_id(blk[1], "id0", false); =20 /* But once job[0] finishes we can reuse its ID */ - block_job_early_fail(job[0]); + job_early_fail(&job[0]->job); job[1] =3D do_test_id(blk[1], "id0", true); =20 /* No job ID specified, defaults to the backend name ('drive1') */ - block_job_early_fail(job[1]); + job_early_fail(&job[1]->job); job[1] =3D do_test_id(blk[1], NULL, true); =20 /* Duplicate job ID */ @@ -145,9 +145,9 @@ static void test_job_ids(void) /* This one is valid */ job[2] =3D do_test_id(blk[2], "id_2", true); =20 - 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); =20 destroy_blk(blk[0]); destroy_blk(blk[1]); --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152458653676596.13027781881544; Tue, 24 Apr 2018 09:15:36 -0700 (PDT) Received: from localhost ([::1]:59405 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0bP-0005vp-Rk for importer@patchew.org; Tue, 24 Apr 2018 12:15:35 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48136) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpT-0008Ih-Jd for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpS-0008V4-D4 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:03 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34864 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpM-0008Lb-O3; Tue, 24 Apr 2018 11:25:56 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 09E0BFA46C; Tue, 24 Apr 2018 15:25:56 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id EF6B0202323A; Tue, 24 Apr 2018 15:25:54 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:07 +0200 Message-Id: <20180424152515.25664-26-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:56 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:56 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 25/33] job: Convert block_job_cancel_async() to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" block_job_cancel_async() did two things that were still block job specific: * Setting job->force. This field makes sense on the Job level, so we can just move it. While at it, rename it to job->force_cancel to make its purpose more obvious. * Resetting the I/O status. This can't be moved because generic Jobs don't have an I/O status. What the function really implements is a user resume, except without entering the coroutine. Consequently, it makes sense to call the .user_resume driver callback here which already resets the I/O status. The old block_job_cancel_async() has two separate if statements that check job->iostatus !=3D BLOCK_DEVICE_IO_STATUS_OK and job->user_paused. However, the former condition always implies the latter (as is asserted in block_job_iostatus_reset()), so changing the explicit call of block_job_iostatus_reset() on the former condition with the .user_resume callback on the latter condition is equivalent and doesn't need to access any BlockJob specific state. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 6 ------ include/qemu/job.h | 6 ++++++ block/mirror.c | 4 ++-- blockjob.c | 25 +++++++++++++------------ 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index e5af02f751..8477fc5a78 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -51,12 +51,6 @@ typedef struct BlockJob { BlockBackend *blk; =20 /** - * Set to true if the job should abort immediately without waiting - * for data to be in sync. - */ - bool force; - - /** * Set to true when the job is ready to be completed. */ bool ready; diff --git a/include/qemu/job.h b/include/qemu/job.h index f456e4f27d..3351627dc0 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -97,6 +97,12 @@ typedef struct Job { */ bool cancelled; =20 + /** + * Set to true if the job should abort immediately without waiting + * for data to be in sync. + */ + bool force_cancel; + /** Set to true when the job has deferred work to the main loop. */ bool deferred_to_main_loop; =20 diff --git a/block/mirror.c b/block/mirror.c index 3266553ffb..8e172e324d 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -865,7 +865,7 @@ static void coroutine_fn mirror_run(void *opaque) =20 ret =3D 0; trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); - if (job_is_cancelled(&s->common.job) && s->common.force) { + if (job_is_cancelled(&s->common.job) && s->common.job.force_cancel= ) { break; } else if (!should_complete) { delay_ns =3D (s->in_flight =3D=3D 0 && cnt =3D=3D 0 ? SLICE_TI= ME : 0); @@ -880,7 +880,7 @@ immediate_exit: * or it was cancelled prematurely so that we do not guarantee that * the target is a copy of the source. */ - assert(ret < 0 || ((s->common.force || !s->synced) && + assert(ret < 0 || ((s->common.job.force_cancel || !s->synced) && job_is_cancelled(&s->common.job))); assert(need_drain); mirror_wait_for_all_io(s); diff --git a/blockjob.c b/blockjob.c index 677938a3b7..17478d2c6e 100644 --- a/blockjob.c +++ b/blockjob.c @@ -271,19 +271,20 @@ static int block_job_prepare(BlockJob *job) return job->job.ret; } =20 -static void block_job_cancel_async(BlockJob *job, bool force) +static void job_cancel_async(Job *job, bool force) { - if (job->iostatus !=3D BLOCK_DEVICE_IO_STATUS_OK) { - block_job_iostatus_reset(job); - } - if (job->job.user_paused) { - /* Do not call block_job_enter here, the caller will handle it. */ - job->job.user_paused =3D false; - job->job.pause_count--; + if (job->user_paused) { + /* Do not call job_enter here, the caller will handle it. */ + job->user_paused =3D false; + if (job->driver->user_resume) { + job->driver->user_resume(job); + } + assert(job->pause_count > 0); + job->pause_count--; } - job->job.cancelled =3D true; + job->cancelled =3D true; /* To prevent 'force =3D=3D false' overriding a previous 'force =3D=3D= true' */ - job->force |=3D force; + job->force_cancel |=3D force; } =20 static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool = lock) @@ -368,7 +369,7 @@ static void block_job_completed_txn_abort(BlockJob *job) * on the caller, so leave it. */ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { if (other_job !=3D job) { - block_job_cancel_async(other_job, false); + job_cancel_async(&other_job->job, false); } } while (!QLIST_EMPTY(&txn->jobs)) { @@ -528,7 +529,7 @@ void block_job_cancel(BlockJob *job, bool force) job_do_dismiss(&job->job); return; } - block_job_cancel_async(job, force); + job_cancel_async(&job->job, force); if (!job_started(&job->job)) { block_job_completed(job, -ECANCELED); } else if (job->job.deferred_to_main_loop) { --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584638419751.3160327475554; Tue, 24 Apr 2018 08:43:58 -0700 (PDT) Received: from localhost ([::1]:59191 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB06i-0005Cs-V8 for importer@patchew.org; Tue, 24 Apr 2018 11:43:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48159) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpU-0008LD-Lp for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:06 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpS-0008VH-E9 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:04 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45636 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpO-0008NH-0f; Tue, 24 Apr 2018 11:25:58 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 54FED407574E; Tue, 24 Apr 2018 15:25:57 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 45500202342F; Tue, 24 Apr 2018 15:25:56 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:08 +0200 Message-Id: <20180424152515.25664-27-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:25:57 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:25:57 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 26/33] job: Add job_drain() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" block_job_drain() contains a blk_drain() call which cannot be moved to Job, so add a new JobDriver callback JobDriver.drain which has a common implementation for all BlockJobs. In addition to this we keep the existing BlockJobDriver.drain callback that is called by the common drain implementation for all block jobs. Signed-off-by: Kevin Wolf --- include/block/blockjob_int.h | 12 ++++++++++++ include/qemu/job.h | 13 +++++++++++++ block/backup.c | 1 + block/commit.c | 1 + block/mirror.c | 2 ++ block/stream.c | 1 + blockjob.c | 20 ++++++++++---------- job.c | 11 +++++++++++ tests/test-bdrv-drain.c | 1 + tests/test-blockjob-txn.c | 1 + tests/test-blockjob.c | 2 ++ 11 files changed, 55 insertions(+), 10 deletions(-) diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 5b0a905c76..c8bcfa917a 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -65,6 +65,10 @@ struct BlockJobDriver { * If the callback is not NULL, it will be invoked when the job has to= be * synchronously cancelled or completed; it should drain BlockDriverSt= ates * as required to ensure progress. + * + * Block jobs must use the default implementation for job_driver.drain, + * which will in turn call this callback after doing generic block job + * stuff. */ void (*drain)(BlockJob *job); }; @@ -112,6 +116,14 @@ void block_job_free(Job *job); void block_job_user_resume(Job *job); =20 /** + * block_job_drain: + * Callback to be used for JobDriver.drain in all block jobs. Drains the m= ain + * block node associated with the block jobs and calls BlockJobDriver.drai= n for + * job-specific actions. + */ +void block_job_drain(Job *job); + +/** * block_job_yield: * @job: The job that calls the function. * diff --git a/include/qemu/job.h b/include/qemu/job.h index 3351627dc0..e73ca7fd43 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -167,6 +167,13 @@ struct JobDriver { */ void (*user_resume)(Job *job); =20 + /* + * If the callback is not NULL, it will be invoked when the job has to= be + * synchronously cancelled or completed; it should drain any activities + * as required to ensure progress. + */ + void (*drain)(Job *job); + /** * If the callback is not NULL, it will be invoked when all the jobs * belonging to the same transaction complete; or upon this job's @@ -308,6 +315,12 @@ bool job_user_paused(Job *job); */ void job_user_resume(Job *job, Error **errp); =20 +/* + * Drain any activities as required to ensure progress. This can be called= in a + * loop to synchronously complete a job. + */ +void job_drain(Job *job); + /** * Get the next element from the list of block jobs after @job, or the * first one if @job is %NULL. diff --git a/block/backup.c b/block/backup.c index 1f17025505..a1ad92fbc3 100644 --- a/block/backup.c +++ b/block/backup.c @@ -529,6 +529,7 @@ static const BlockJobDriver backup_job_driver =3D { .job_type =3D JOB_TYPE_BACKUP, .free =3D block_job_free, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, .start =3D backup_run, .commit =3D backup_commit, .abort =3D backup_abort, diff --git a/block/commit.c b/block/commit.c index e53b2d7d55..02a8af9127 100644 --- a/block/commit.c +++ b/block/commit.c @@ -221,6 +221,7 @@ static const BlockJobDriver commit_job_driver =3D { .job_type =3D JOB_TYPE_COMMIT, .free =3D block_job_free, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, .start =3D commit_run, }, }; diff --git a/block/mirror.c b/block/mirror.c index 8e172e324d..5a83973661 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -988,6 +988,7 @@ static const BlockJobDriver mirror_job_driver =3D { .job_type =3D JOB_TYPE_MIRROR, .free =3D block_job_free, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, .start =3D mirror_run, .pause =3D mirror_pause, }, @@ -1002,6 +1003,7 @@ static const BlockJobDriver commit_active_job_driver = =3D { .job_type =3D JOB_TYPE_COMMIT, .free =3D block_job_free, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, .start =3D mirror_run, .pause =3D mirror_pause, }, diff --git a/block/stream.c b/block/stream.c index eee02538ed..b996278ab3 100644 --- a/block/stream.c +++ b/block/stream.c @@ -215,6 +215,7 @@ static const BlockJobDriver stream_job_driver =3D { .free =3D block_job_free, .start =3D stream_run, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, }, }; =20 diff --git a/blockjob.c b/blockjob.c index 17478d2c6e..e211127b79 100644 --- a/blockjob.c +++ b/blockjob.c @@ -170,14 +170,13 @@ static void block_job_attached_aio_context(AioContext= *new_context, job_resume(&job->job); } =20 -static void block_job_drain(BlockJob *job) +void block_job_drain(Job *job) { - /* If job is !job->job.busy this kicks it into the next pause point. */ - block_job_enter(job); + BlockJob *bjob =3D container_of(job, BlockJob, job); =20 - blk_drain(job->blk); - if (job->driver->drain) { - job->driver->drain(job); + blk_drain(bjob->blk); + if (bjob->driver->drain) { + bjob->driver->drain(bjob); } } =20 @@ -191,7 +190,7 @@ static void block_job_detach_aio_context(void *opaque) job_pause(&job->job); =20 while (!job->job.paused && !job_is_completed(&job->job)) { - block_job_drain(job); + job_drain(&job->job); } =20 job->job.aio_context =3D NULL; @@ -328,11 +327,11 @@ static int block_job_finish_sync(BlockJob *job, job_unref(&job->job); return -EBUSY; } - /* block_job_drain calls block_job_enter, and it should be enough to - * induce progress until the job completes or moves to the main thread. + /* job_drain calls job_enter, and it should be enough to induce progre= ss + * until the job completes or moves to the main thread. */ while (!job->job.deferred_to_main_loop && !job_is_completed(&job->job)= ) { - block_job_drain(job); + job_drain(&job->job); } while (!job_is_completed(&job->job)) { aio_poll(qemu_get_aio_context(), true); @@ -712,6 +711,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, assert(is_block_job(&job->job)); assert(job->job.driver->free =3D=3D &block_job_free); assert(job->job.driver->user_resume =3D=3D &block_job_user_resume); + assert(job->job.driver->drain =3D=3D &block_job_drain); =20 job->driver =3D driver; job->blk =3D blk; diff --git a/job.c b/job.c index 0ad8f29982..dc7a54bbbc 100644 --- a/job.c +++ b/job.c @@ -375,6 +375,17 @@ void coroutine_fn job_sleep_ns(Job *job, int64_t ns) job_pause_point(job); } =20 +void job_drain(Job *job) +{ + /* If job is !busy this kicks it into the next pause point. */ + job_enter(job); + + if (job->driver->drain) { + job->driver->drain(job); + } +} + + /** * All jobs must allow a pause point before entering their job proper. This * ensures that jobs can be paused prior to being started, then resumed la= ter. diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index c993512f66..58ea5663f0 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -525,6 +525,7 @@ BlockJobDriver test_job_driver =3D { .instance_size =3D sizeof(TestBlockJob), .free =3D block_job_free, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, .start =3D test_job_start, }, .complete =3D test_job_complete, diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 60e9fa2298..1572f8d96f 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -79,6 +79,7 @@ static const BlockJobDriver test_block_job_driver =3D { .instance_size =3D sizeof(TestBlockJob), .free =3D block_job_free, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, .start =3D test_block_job_run, }, }; diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 1fe6803fe0..592a13613d 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -21,6 +21,7 @@ static const BlockJobDriver test_block_job_driver =3D { .instance_size =3D sizeof(BlockJob), .free =3D block_job_free, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, }, }; =20 @@ -201,6 +202,7 @@ static const BlockJobDriver test_cancel_driver =3D { .instance_size =3D sizeof(CancelJob), .free =3D block_job_free, .user_resume =3D block_job_user_resume, + .drain =3D block_job_drain, .start =3D cancel_job_start, }, .complete =3D cancel_job_complete, --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585421214831.5615881868225; Tue, 24 Apr 2018 08:57:01 -0700 (PDT) Received: from localhost ([::1]:59277 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0JQ-0007bm-Aq for importer@patchew.org; Tue, 24 Apr 2018 11:57:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48184) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpW-0008NV-Cr for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpU-00006r-Cw for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:06 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59842 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpP-0008PS-3I; Tue, 24 Apr 2018 11:25:59 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9FAF6406C7AC; Tue, 24 Apr 2018 15:25:58 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9054E2026990; Tue, 24 Apr 2018 15:25:57 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:09 +0200 Message-Id: <20180424152515.25664-28-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:58 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 24 Apr 2018 15:25:58 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 27/33] job: Move .complete callback to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves the .complete callback that tells a READY job to complete from BlockJobDriver to JobDriver. The wrapper function job_complete() doesn't require anything block job specific any more and can be moved to Job. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 10 ---------- include/block/blockjob_int.h | 6 ------ include/qemu/job.h | 8 ++++++++ block/mirror.c | 10 +++++----- blockdev.c | 2 +- blockjob.c | 23 +++++------------------ job.c | 16 ++++++++++++++++ tests/test-bdrv-drain.c | 6 +++--- tests/test-blockjob.c | 10 +++++----- 9 files changed, 43 insertions(+), 48 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 8477fc5a78..91fdbc9042 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -154,16 +154,6 @@ void block_job_set_speed(BlockJob *job, int64_t speed,= Error **errp); void block_job_cancel(BlockJob *job, bool force); =20 /** - * block_job_complete: - * @job: The job to be completed. - * @errp: Error object. - * - * Asynchronously complete the specified job. - */ -void block_job_complete(BlockJob *job, Error **errp); - - -/** * block_job_finalize: * @job: The job to fully commit and finish. * @errp: Error object. diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index c8bcfa917a..fb81d7a09f 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -39,12 +39,6 @@ struct BlockJobDriver { JobDriver job_driver; =20 /** - * Optional callback for job types whose completion must be triggered - * manually. - */ - void (*complete)(BlockJob *job, Error **errp); - - /** * If the callback is not NULL, prepare will be invoked when all the j= obs * belonging to the same transaction complete; or upon this job's comp= letion * if it is not in a transaction. diff --git a/include/qemu/job.h b/include/qemu/job.h index e73ca7fd43..6132cf8e21 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -167,6 +167,12 @@ struct JobDriver { */ void (*user_resume)(Job *job); =20 + /** + * Optional callback for job types whose completion must be triggered + * manually. + */ + void (*complete)(Job *job, Error **errp); + /* * If the callback is not NULL, it will be invoked when the job has to= be * synchronously cancelled or completed; it should drain any activities @@ -339,6 +345,8 @@ Job *job_get(const char *id); /** The @job could not be started, free it. */ void job_early_fail(Job *job); =20 +/** Asynchronously complete the specified @job. */ +void job_complete(Job *job, Error **errp);; =20 typedef void JobDeferToMainLoopFn(Job *job, void *opaque); =20 diff --git a/block/mirror.c b/block/mirror.c index 5a83973661..9eb5a21cd9 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -901,16 +901,16 @@ immediate_exit: job_defer_to_main_loop(&s->common.job, mirror_exit, data); } =20 -static void mirror_complete(BlockJob *job, Error **errp) +static void mirror_complete(Job *job, Error **errp) { - MirrorBlockJob *s =3D container_of(job, MirrorBlockJob, common); + MirrorBlockJob *s =3D container_of(job, MirrorBlockJob, common.job); BlockDriverState *target; =20 target =3D blk_bs(s->target); =20 if (!s->synced) { error_setg(errp, "The active block job '%s' cannot be completed", - job->job.id); + job->id); return; } =20 @@ -991,8 +991,8 @@ static const BlockJobDriver mirror_job_driver =3D { .drain =3D block_job_drain, .start =3D mirror_run, .pause =3D mirror_pause, + .complete =3D mirror_complete, }, - .complete =3D mirror_complete, .attached_aio_context =3D mirror_attached_aio_context, .drain =3D mirror_drain, }; @@ -1006,8 +1006,8 @@ static const BlockJobDriver commit_active_job_driver = =3D { .drain =3D block_job_drain, .start =3D mirror_run, .pause =3D mirror_pause, + .complete =3D mirror_complete, }, - .complete =3D mirror_complete, .attached_aio_context =3D mirror_attached_aio_context, .drain =3D mirror_drain, }; diff --git a/blockdev.c b/blockdev.c index fb7a3142e7..31aac7dae6 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3894,7 +3894,7 @@ void qmp_block_job_complete(const char *device, Error= **errp) } =20 trace_qmp_block_job_complete(job); - block_job_complete(job, errp); + job_complete(&job->job, errp); aio_context_release(aio_context); } =20 diff --git a/blockjob.c b/blockjob.c index e211127b79..f4010988d4 100644 --- a/blockjob.c +++ b/blockjob.c @@ -482,24 +482,6 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, u= int64_t n) return ratelimit_calculate_delay(&job->limit, n); } =20 -void block_job_complete(BlockJob *job, Error **errp) -{ - /* Should not be reachable via external interface for internal jobs */ - assert(job->job.id); - if (job_apply_verb(&job->job, JOB_VERB_COMPLETE, errp)) { - return; - } - if (job->job.pause_count || job_is_cancelled(&job->job) || - !job->driver->complete) - { - error_setg(errp, "The active block job '%s' cannot be completed", - job->job.id); - return; - } - - job->driver->complete(job, errp); -} - void block_job_finalize(BlockJob *job, Error **errp) { assert(job && job->job.id && job->txn); @@ -572,6 +554,11 @@ void block_job_cancel_sync_all(void) } } =20 +static void block_job_complete(BlockJob *job, Error **errp) +{ + job_complete(&job->job, errp); +} + int block_job_complete_sync(BlockJob *job, Error **errp) { return block_job_finish_sync(job, &block_job_complete, errp); diff --git a/job.c b/job.c index dc7a54bbbc..dd68eb13f7 100644 --- a/job.c +++ b/job.c @@ -556,6 +556,22 @@ int job_finalize_single(Job *job) return 0; } =20 +void job_complete(Job *job, Error **errp) +{ + /* Should not be reachable via external interface for internal jobs */ + assert(job->id); + if (job_apply_verb(job, JOB_VERB_COMPLETE, errp)) { + return; + } + if (job->pause_count || job_is_cancelled(job) || !job->driver->complet= e) { + error_setg(errp, "The active block job '%s' cannot be completed", + job->id); + return; + } + + job->driver->complete(job, errp); +} + =20 typedef struct { Job *job; diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 58ea5663f0..b428aaca68 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -514,9 +514,9 @@ static void coroutine_fn test_job_start(void *opaque) job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); } =20 -static void test_job_complete(BlockJob *job, Error **errp) +static void test_job_complete(Job *job, Error **errp) { - TestBlockJob *s =3D container_of(job, TestBlockJob, common); + TestBlockJob *s =3D container_of(job, TestBlockJob, common.job); s->should_complete =3D true; } =20 @@ -527,8 +527,8 @@ BlockJobDriver test_job_driver =3D { .user_resume =3D block_job_user_resume, .drain =3D block_job_drain, .start =3D test_job_start, + .complete =3D test_job_complete, }, - .complete =3D test_job_complete, }; =20 static void test_blockjob_common(enum drain_type drain_type) diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 592a13613d..e44c608327 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -171,9 +171,9 @@ static void cancel_job_completed(Job *job, void *opaque) block_job_completed(bjob, 0); } =20 -static void cancel_job_complete(BlockJob *job, Error **errp) +static void cancel_job_complete(Job *job, Error **errp) { - CancelJob *s =3D container_of(job, CancelJob, common); + CancelJob *s =3D container_of(job, CancelJob, common.job); s->should_complete =3D true; } =20 @@ -204,8 +204,8 @@ static const BlockJobDriver test_cancel_driver =3D { .user_resume =3D block_job_user_resume, .drain =3D block_job_drain, .start =3D cancel_job_start, + .complete =3D cancel_job_complete, }, - .complete =3D cancel_job_complete, }; =20 static CancelJob *create_common(BlockJob **pjob) @@ -333,7 +333,7 @@ static void test_cancel_pending(void) block_job_enter(job); assert(job->job.status =3D=3D JOB_STATUS_READY); =20 - block_job_complete(job, &error_abort); + job_complete(&job->job, &error_abort); block_job_enter(job); while (!s->completed) { aio_poll(qemu_get_aio_context(), true); @@ -357,7 +357,7 @@ static void test_cancel_concluded(void) block_job_enter(job); assert(job->job.status =3D=3D JOB_STATUS_READY); =20 - block_job_complete(job, &error_abort); + job_complete(&job->job, &error_abort); block_job_enter(job); while (!s->completed) { aio_poll(qemu_get_aio_context(), true); --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585252650500.2763897411728; Tue, 24 Apr 2018 08:54:12 -0700 (PDT) Received: from localhost ([::1]:59258 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Gh-000584-Mt for importer@patchew.org; Tue, 24 Apr 2018 11:54:11 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48164) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpV-0008Lk-3a for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:06 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpT-00005p-L9 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:05 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34866 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpQ-0008Qp-AZ; Tue, 24 Apr 2018 11:26:00 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EB549F080F; Tue, 24 Apr 2018 15:25:59 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id DAE90202342F; Tue, 24 Apr 2018 15:25:58 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:10 +0200 Message-Id: <20180424152515.25664-29-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:59 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:25:59 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 28/33] job: Move job_finish_sync() to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" block_job_finish_sync() doesn't contain anything block job specific any more, so it can be moved to Job. Signed-off-by: Kevin Wolf --- include/qemu/job.h | 9 +++++++++ blockjob.c | 55 +++++++++-----------------------------------------= ---- job.c | 28 +++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/include/qemu/job.h b/include/qemu/job.h index 6132cf8e21..c5a5d0cfdb 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -365,6 +365,15 @@ typedef void JobDeferToMainLoopFn(Job *job, void *opaq= ue); */ void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaq= ue); =20 +/** + * Synchronously finishes the given @job. If @finish is given, it is calle= d to + * trigger completion or cancellation of the job. + * + * Returns 0 if the job is successfully completed, -ECANCELED if the job w= as + * cancelled before completing, and -errno in other error cases. + */ +int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error *= *errp); + /* TODO To be removed from the public interface */ void job_state_transition(Job *job, JobStatus s1); int job_apply_verb(Job *job, JobVerb bv, Error **errp); diff --git a/blockjob.c b/blockjob.c index f4010988d4..5d91070cd2 100644 --- a/blockjob.c +++ b/blockjob.c @@ -308,40 +308,6 @@ static int block_job_txn_apply(BlockJobTxn *txn, int f= n(BlockJob *), bool lock) return rc; } =20 -static int block_job_finish_sync(BlockJob *job, - void (*finish)(BlockJob *, Error **errp), - Error **errp) -{ - Error *local_err =3D NULL; - int ret; - - assert(blk_bs(job->blk)->job =3D=3D job); - - job_ref(&job->job); - - if (finish) { - finish(job, &local_err); - } - if (local_err) { - error_propagate(errp, local_err); - job_unref(&job->job); - return -EBUSY; - } - /* job_drain calls job_enter, and it should be enough to induce progre= ss - * until the job completes or moves to the main thread. - */ - while (!job->job.deferred_to_main_loop && !job_is_completed(&job->job)= ) { - job_drain(&job->job); - } - while (!job_is_completed(&job->job)) { - aio_poll(qemu_get_aio_context(), true); - } - ret =3D (job_is_cancelled(&job->job) && job->job.ret =3D=3D 0) - ? -ECANCELED : job->job.ret; - job_unref(&job->job); - return ret; -} - static void block_job_completed_txn_abort(BlockJob *job) { AioContext *ctx; @@ -376,7 +342,7 @@ static void block_job_completed_txn_abort(BlockJob *job) ctx =3D blk_get_aio_context(other_job->blk); if (!job_is_completed(&other_job->job)) { assert(job_is_cancelled(&other_job->job)); - block_job_finish_sync(other_job, NULL, NULL); + job_finish_sync(&other_job->job, NULL, NULL); } job_finalize_single(&other_job->job); aio_context_release(ctx); @@ -529,16 +495,18 @@ void block_job_user_cancel(BlockJob *job, bool force,= Error **errp) } =20 /* A wrapper around block_job_cancel() taking an Error ** parameter so it = may be - * used with block_job_finish_sync() without the need for (rather nasty) - * function pointer casts there. */ -static void block_job_cancel_err(BlockJob *job, Error **errp) + * used with job_finish_sync() without the need for (rather nasty) function + * pointer casts there. */ +static void block_job_cancel_err(Job *job, Error **errp) { - block_job_cancel(job, false); + BlockJob *bjob =3D container_of(job, BlockJob, job); + assert(is_block_job(job)); + block_job_cancel(bjob, false); } =20 int block_job_cancel_sync(BlockJob *job) { - return block_job_finish_sync(job, &block_job_cancel_err, NULL); + return job_finish_sync(&job->job, &block_job_cancel_err, NULL); } =20 void block_job_cancel_sync_all(void) @@ -554,14 +522,9 @@ void block_job_cancel_sync_all(void) } } =20 -static void block_job_complete(BlockJob *job, Error **errp) -{ - job_complete(&job->job, errp); -} - int block_job_complete_sync(BlockJob *job, Error **errp) { - return block_job_finish_sync(job, &block_job_complete, errp); + return job_finish_sync(&job->job, job_complete, errp); } =20 void block_job_progress_update(BlockJob *job, uint64_t done) diff --git a/job.c b/job.c index dd68eb13f7..db3d8536f7 100644 --- a/job.c +++ b/job.c @@ -604,3 +604,31 @@ void job_defer_to_main_loop(Job *job, JobDeferToMainLo= opFn *fn, void *opaque) aio_bh_schedule_oneshot(qemu_get_aio_context(), job_defer_to_main_loop_bh, data); } + +int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error *= *errp) +{ + Error *local_err =3D NULL; + int ret; + + job_ref(job); + + if (finish) { + finish(job, &local_err); + } + if (local_err) { + error_propagate(errp, local_err); + job_unref(job); + return -EBUSY; + } + /* job_drain calls job_enter, and it should be enough to induce progre= ss + * until the job completes or moves to the main thread. */ + while (!job->deferred_to_main_loop && !job_is_completed(job)) { + job_drain(job); + } + while (!job_is_completed(job)) { + aio_poll(qemu_get_aio_context(), true); + } + ret =3D (job_is_cancelled(job) && job->ret =3D=3D 0) ? -ECANCELED : jo= b->ret; + job_unref(job); + return ret; +} --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524586818839697.7262373433385; Tue, 24 Apr 2018 09:20:18 -0700 (PDT) Received: from localhost ([::1]:59430 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0fy-0000vF-04 for importer@patchew.org; Tue, 24 Apr 2018 12:20:18 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48292) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpd-0008Vz-F3 for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpb-0000KK-Dl for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:13 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45638 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpR-0008TY-KR; Tue, 24 Apr 2018 11:26:01 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 43342406E8B9; Tue, 24 Apr 2018 15:26:01 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 32B63202342F; Tue, 24 Apr 2018 15:26:00 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:11 +0200 Message-Id: <20180424152515.25664-30-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:26:01 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:26:01 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 29/33] job: Switch transactions to JobTxn X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This doesn't actually move any transaction code to Job yet, but it renames the type for transactions from BlockJobTxn to JobTxn and makes them contain Jobs rather than BlockJobs Signed-off-by: Kevin Wolf --- include/block/block_int.h | 2 +- include/block/blockjob.h | 11 ++++---- include/block/blockjob_int.h | 2 +- include/qemu/job.h | 3 +++ block/backup.c | 2 +- blockdev.c | 14 +++++------ blockjob.c | 60 +++++++++++++++++++++++-----------------= ---- tests/test-blockjob-txn.c | 8 +++--- 8 files changed, 54 insertions(+), 48 deletions(-) diff --git a/include/block/block_int.h b/include/block/block_int.h index c4dd1d4bb8..dc1666c0c4 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1017,7 +1017,7 @@ BlockJob *backup_job_create(const char *job_id, Block= DriverState *bs, BlockdevOnError on_target_error, int creation_flags, BlockCompletionFunc *cb, void *opaque, - BlockJobTxn *txn, Error **errp); + JobTxn *txn, Error **errp); =20 void hmp_drive_add_node(Monitor *mon, const char *optstr); =20 diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 91fdbc9042..fbb8f54dc6 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -33,7 +33,7 @@ #define SLICE_TIME 100000000ULL /* ns */ =20 typedef struct BlockJobDriver BlockJobDriver; -typedef struct BlockJobTxn BlockJobTxn; +typedef struct JobTxn JobTxn; =20 /** * BlockJob: @@ -85,8 +85,7 @@ typedef struct BlockJob { /** BlockDriverStates that are involved in this block job */ GSList *nodes; =20 - BlockJobTxn *txn; - QLIST_ENTRY(BlockJob) txn_list; + JobTxn *txn; } BlockJob; =20 /** @@ -273,7 +272,7 @@ void block_job_iostatus_reset(BlockJob *job); * group. Jobs wait for each other before completing. Cancelling one job * cancels all jobs in the transaction. */ -BlockJobTxn *block_job_txn_new(void); +JobTxn *block_job_txn_new(void); =20 /** * block_job_txn_unref: @@ -282,7 +281,7 @@ BlockJobTxn *block_job_txn_new(void); * or block_job_txn_new. If it's the last reference to the object, it will= be * freed. */ -void block_job_txn_unref(BlockJobTxn *txn); +void block_job_txn_unref(JobTxn *txn); =20 /** * block_job_txn_add_job: @@ -293,7 +292,7 @@ void block_job_txn_unref(BlockJobTxn *txn); * The caller must call either block_job_txn_unref() or block_job_complete= d() * to release the reference that is automatically grabbed here. */ -void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job); +void block_job_txn_add_job(JobTxn *txn, BlockJob *job); =20 /** * block_job_is_internal: diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index fb81d7a09f..13c9924b9c 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -91,7 +91,7 @@ struct BlockJobDriver { * called from a wrapper that is specific to the job type. */ void *block_job_create(const char *job_id, const BlockJobDriver *driver, - BlockJobTxn *txn, BlockDriverState *bs, uint64_t pe= rm, + JobTxn *txn, BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, int64_t speed, int flags, BlockCompletionFunc *cb, void *opaque, Error **errp= ); =20 diff --git a/include/qemu/job.h b/include/qemu/job.h index c5a5d0cfdb..0c8e7e85d0 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -132,6 +132,9 @@ typedef struct Job { =20 /** Element of the list of jobs */ QLIST_ENTRY(Job) job_list; + + /** Element of the list of jobs in a job transaction */ + QLIST_ENTRY(Job) txn_list; } Job; =20 /** diff --git a/block/backup.c b/block/backup.c index a1ad92fbc3..f83b14d8dc 100644 --- a/block/backup.c +++ b/block/backup.c @@ -547,7 +547,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDr= iverState *bs, BlockdevOnError on_target_error, int creation_flags, BlockCompletionFunc *cb, void *opaque, - BlockJobTxn *txn, Error **errp) + JobTxn *txn, Error **errp) { int64_t len; BlockDriverInfo bdi; diff --git a/blockdev.c b/blockdev.c index 31aac7dae6..69471c62b3 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1446,7 +1446,7 @@ typedef struct BlkActionOps { struct BlkActionState { TransactionAction *action; const BlkActionOps *ops; - BlockJobTxn *block_job_txn; + JobTxn *block_job_txn; TransactionProperties *txn_props; QSIMPLEQ_ENTRY(BlkActionState) entry; }; @@ -1864,7 +1864,7 @@ typedef struct DriveBackupState { BlockJob *job; } DriveBackupState; =20 -static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, +static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, Error **errp); =20 static void drive_backup_prepare(BlkActionState *common, Error **errp) @@ -1954,7 +1954,7 @@ typedef struct BlockdevBackupState { BlockJob *job; } BlockdevBackupState; =20 -static BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *t= xn, +static BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, Error **errp); =20 static void blockdev_backup_prepare(BlkActionState *common, Error **errp) @@ -2243,7 +2243,7 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp) { TransactionActionList *dev_entry =3D dev_list; - BlockJobTxn *block_job_txn =3D NULL; + JobTxn *block_job_txn =3D NULL; BlkActionState *state, *next; Error *local_err =3D NULL; =20 @@ -2251,7 +2251,7 @@ void qmp_transaction(TransactionActionList *dev_list, QSIMPLEQ_INIT(&snap_bdrv_states); =20 /* Does this transaction get canceled as a group on failure? - * If not, we don't really need to make a BlockJobTxn. + * If not, we don't really need to make a JobTxn. */ props =3D get_transaction_properties(props); if (props->completion_mode !=3D ACTION_COMPLETION_MODE_INDIVIDUAL) { @@ -3264,7 +3264,7 @@ out: aio_context_release(aio_context); } =20 -static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, +static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, Error **errp) { BlockDriverState *bs; @@ -3434,7 +3434,7 @@ BlockDeviceInfoList *qmp_query_named_block_nodes(Erro= r **errp) return bdrv_named_nodes_list(errp); } =20 -BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, +BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, Error **errp) { BlockDriverState *bs; diff --git a/blockjob.c b/blockjob.c index 5d91070cd2..3afa0dbdca 100644 --- a/blockjob.c +++ b/blockjob.c @@ -37,13 +37,13 @@ #include "qemu/timer.h" =20 /* Transactional group of block jobs */ -struct BlockJobTxn { +struct JobTxn { =20 /* Is this txn being cancelled? */ bool aborting; =20 /* List of jobs */ - QLIST_HEAD(, BlockJob) jobs; + QLIST_HEAD(, Job) jobs; =20 /* Reference count */ int refcnt; @@ -95,27 +95,27 @@ BlockJob *block_job_get(const char *id) } } =20 -BlockJobTxn *block_job_txn_new(void) +JobTxn *block_job_txn_new(void) { - BlockJobTxn *txn =3D g_new0(BlockJobTxn, 1); + JobTxn *txn =3D g_new0(JobTxn, 1); QLIST_INIT(&txn->jobs); txn->refcnt =3D 1; return txn; } =20 -static void block_job_txn_ref(BlockJobTxn *txn) +static void block_job_txn_ref(JobTxn *txn) { txn->refcnt++; } =20 -void block_job_txn_unref(BlockJobTxn *txn) +void block_job_txn_unref(JobTxn *txn) { if (txn && --txn->refcnt =3D=3D 0) { g_free(txn); } } =20 -void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job) +void block_job_txn_add_job(JobTxn *txn, BlockJob *job) { if (!txn) { return; @@ -124,14 +124,14 @@ void block_job_txn_add_job(BlockJobTxn *txn, BlockJob= *job) assert(!job->txn); job->txn =3D txn; =20 - QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); + QLIST_INSERT_HEAD(&txn->jobs, &job->job, txn_list); block_job_txn_ref(txn); } =20 void block_job_txn_del_job(BlockJob *job) { if (job->txn) { - QLIST_REMOVE(job, txn_list); + QLIST_REMOVE(&job->job, txn_list); block_job_txn_unref(job->txn); job->txn =3D NULL; } @@ -286,18 +286,22 @@ static void job_cancel_async(Job *job, bool force) job->force_cancel |=3D force; } =20 -static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool = lock) +static int block_job_txn_apply(JobTxn *txn, int fn(BlockJob *), bool lock) { AioContext *ctx; - BlockJob *job, *next; + Job *job, *next; + BlockJob *bjob; int rc =3D 0; =20 QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { + assert(is_block_job(job)); + bjob =3D container_of(job, BlockJob, job); + if (lock) { - ctx =3D blk_get_aio_context(job->blk); + ctx =3D job->aio_context; aio_context_acquire(ctx); } - rc =3D fn(job); + rc =3D fn(bjob); if (lock) { aio_context_release(ctx); } @@ -311,8 +315,8 @@ static int block_job_txn_apply(BlockJobTxn *txn, int fn= (BlockJob *), bool lock) static void block_job_completed_txn_abort(BlockJob *job) { AioContext *ctx; - BlockJobTxn *txn =3D job->txn; - BlockJob *other_job; + JobTxn *txn =3D job->txn; + Job *other_job; =20 if (txn->aborting) { /* @@ -325,7 +329,7 @@ static void block_job_completed_txn_abort(BlockJob *job) =20 /* We are the first failed job. Cancel other jobs. */ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - ctx =3D blk_get_aio_context(other_job->blk); + ctx =3D other_job->aio_context; aio_context_acquire(ctx); } =20 @@ -333,18 +337,18 @@ static void block_job_completed_txn_abort(BlockJob *j= ob) * them; this job, however, may or may not be cancelled, depending * on the caller, so leave it. */ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - if (other_job !=3D job) { - job_cancel_async(&other_job->job, false); + if (other_job !=3D &job->job) { + job_cancel_async(other_job, false); } } while (!QLIST_EMPTY(&txn->jobs)) { other_job =3D QLIST_FIRST(&txn->jobs); - ctx =3D blk_get_aio_context(other_job->blk); - if (!job_is_completed(&other_job->job)) { - assert(job_is_cancelled(&other_job->job)); - job_finish_sync(&other_job->job, NULL, NULL); + ctx =3D other_job->aio_context; + if (!job_is_completed(other_job)) { + assert(job_is_cancelled(other_job)); + job_finish_sync(other_job, NULL, NULL); } - job_finalize_single(&other_job->job); + job_finalize_single(other_job); aio_context_release(ctx); } =20 @@ -386,8 +390,8 @@ static int block_job_transition_to_pending(BlockJob *jo= b) =20 static void block_job_completed_txn_success(BlockJob *job) { - BlockJobTxn *txn =3D job->txn; - BlockJob *other_job; + JobTxn *txn =3D job->txn; + Job *other_job; =20 job_state_transition(&job->job, JOB_STATUS_WAITING); =20 @@ -396,10 +400,10 @@ static void block_job_completed_txn_success(BlockJob = *job) * txn. */ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - if (!job_is_completed(&other_job->job)) { + if (!job_is_completed(other_job)) { return; } - assert(other_job->job.ret =3D=3D 0); + assert(other_job->ret =3D=3D 0); } =20 block_job_txn_apply(txn, block_job_transition_to_pending, false); @@ -627,7 +631,7 @@ static void block_job_event_pending(Notifier *n, void *= opaque) */ =20 void *block_job_create(const char *job_id, const BlockJobDriver *driver, - BlockJobTxn *txn, BlockDriverState *bs, uint64_t pe= rm, + JobTxn *txn, BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, int64_t speed, int flags, BlockCompletionFunc *cb, void *opaque, Error **errp) { diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 1572f8d96f..ec5d592b68 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -93,7 +93,7 @@ static const BlockJobDriver test_block_job_driver =3D { */ static BlockJob *test_block_job_start(unsigned int iterations, bool use_timer, - int rc, int *result, BlockJobTxn *tx= n) + int rc, int *result, JobTxn *txn) { BlockDriverState *bs; TestBlockJob *s; @@ -122,7 +122,7 @@ static BlockJob *test_block_job_start(unsigned int iter= ations, static void test_single_job(int expected) { BlockJob *job; - BlockJobTxn *txn; + JobTxn *txn; int result =3D -EINPROGRESS; =20 txn =3D block_job_txn_new(); @@ -160,7 +160,7 @@ static void test_pair_jobs(int expected1, int expected2) { BlockJob *job1; BlockJob *job2; - BlockJobTxn *txn; + JobTxn *txn; int result1 =3D -EINPROGRESS; int result2 =3D -EINPROGRESS; =20 @@ -222,7 +222,7 @@ static void test_pair_jobs_fail_cancel_race(void) { BlockJob *job1; BlockJob *job2; - BlockJobTxn *txn; + JobTxn *txn; int result1 =3D -EINPROGRESS; int result2 =3D -EINPROGRESS; =20 --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585015490942.0713059262844; Tue, 24 Apr 2018 08:50:15 -0700 (PDT) Received: from localhost ([::1]:59229 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0Cs-0001pL-H2 for importer@patchew.org; Tue, 24 Apr 2018 11:50:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48327) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzph-00008m-Fq for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpe-0000Oi-CC for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:17 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:58904 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpS-0008Vk-VD; Tue, 24 Apr 2018 11:26:03 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 90EB940201DF; Tue, 24 Apr 2018 15:26:02 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7ED912026990; Tue, 24 Apr 2018 15:26:01 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:12 +0200 Message-Id: <20180424152515.25664-31-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 24 Apr 2018 15:26:02 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 24 Apr 2018 15:26:02 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 30/33] job: Move transactions to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves the logic that implements job transactions from BlockJob to Job. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 54 ---------- include/block/blockjob_int.h | 10 -- include/qemu/job.h | 70 +++++++++++-- blockdev.c | 6 +- blockjob.c | 238 +--------------------------------------= ---- job.c | 233 +++++++++++++++++++++++++++++++++++++++= +-- tests/test-blockjob-txn.c | 12 +-- tests/test-blockjob.c | 2 +- 8 files changed, 303 insertions(+), 322 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index fbb8f54dc6..e8e9e5f370 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -33,7 +33,6 @@ #define SLICE_TIME 100000000ULL /* ns */ =20 typedef struct BlockJobDriver BlockJobDriver; -typedef struct JobTxn JobTxn; =20 /** * BlockJob: @@ -84,8 +83,6 @@ typedef struct BlockJob { =20 /** BlockDriverStates that are involved in this block job */ GSList *nodes; - - JobTxn *txn; } BlockJob; =20 /** @@ -153,22 +150,6 @@ void block_job_set_speed(BlockJob *job, int64_t speed,= Error **errp); void block_job_cancel(BlockJob *job, bool force); =20 /** - * block_job_finalize: - * @job: The job to fully commit and finish. - * @errp: Error object. - * - * For jobs that have finished their work and are pending - * awaiting explicit acknowledgement to commit their work, - * This will commit that work. - * - * FIXME: Make the below statement universally true: - * For jobs that support the manual workflow mode, all graph - * changes that occur as a result will occur after this command - * and before a successful reply. - */ -void block_job_finalize(BlockJob *job, Error **errp); - -/** * block_job_dismiss: * @job: The job to be dismissed. * @errp: Error object. @@ -260,41 +241,6 @@ int block_job_complete_sync(BlockJob *job, Error **err= p); void block_job_iostatus_reset(BlockJob *job); =20 /** - * block_job_txn_new: - * - * Allocate and return a new block job transaction. Jobs can be added to = the - * transaction using block_job_txn_add_job(). - * - * The transaction is automatically freed when the last job completes or is - * cancelled. - * - * All jobs in the transaction either complete successfully or fail/cancel= as a - * group. Jobs wait for each other before completing. Cancelling one job - * cancels all jobs in the transaction. - */ -JobTxn *block_job_txn_new(void); - -/** - * block_job_txn_unref: - * - * Release a reference that was previously acquired with block_job_txn_add= _job - * or block_job_txn_new. If it's the last reference to the object, it will= be - * freed. - */ -void block_job_txn_unref(JobTxn *txn); - -/** - * block_job_txn_add_job: - * @txn: The transaction (may be NULL) - * @job: Job to add to the transaction - * - * Add @job to the transaction. The @job must not already be in a transac= tion. - * The caller must call either block_job_txn_unref() or block_job_complete= d() - * to release the reference that is automatically grabbed here. - */ -void block_job_txn_add_job(JobTxn *txn, BlockJob *job); - -/** * block_job_is_internal: * @job: The job to determine if it is user-visible or not. * diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 13c9924b9c..2519b1f879 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -38,16 +38,6 @@ struct BlockJobDriver { /** Generic JobDriver callbacks and settings */ JobDriver job_driver; =20 - /** - * If the callback is not NULL, prepare will be invoked when all the j= obs - * belonging to the same transaction complete; or upon this job's comp= letion - * if it is not in a transaction. - * - * This callback will not be invoked if the job has already failed. - * If it fails, abort and then clean will be called. - */ - int (*prepare)(BlockJob *job); - /* * If the callback is not NULL, it will be invoked before the job is * resumed in a new AioContext. This is the place to move any resourc= es diff --git a/include/qemu/job.h b/include/qemu/job.h index 0c8e7e85d0..fceb18c6c7 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -32,6 +32,8 @@ #include "block/aio.h" =20 typedef struct JobDriver JobDriver; +typedef struct JobTxn JobTxn; + =20 /** * Long-running operation. @@ -133,6 +135,9 @@ typedef struct Job { /** Element of the list of jobs */ QLIST_ENTRY(Job) job_list; =20 + /** Transaction this job is part of */ + JobTxn *txn; + /** Element of the list of jobs in a job transaction */ QLIST_ENTRY(Job) txn_list; } Job; @@ -184,6 +189,16 @@ struct JobDriver { void (*drain)(Job *job); =20 /** + * If the callback is not NULL, prepare will be invoked when all the j= obs + * belonging to the same transaction complete; or upon this job's comp= letion + * if it is not in a transaction. + * + * This callback will not be invoked if the job has already failed. + * If it fails, abort and then clean will be called. + */ + int (*prepare)(Job *job); + + /** * If the callback is not NULL, it will be invoked when all the jobs * belonging to the same transaction complete; or upon this job's * completion if it is not in a transaction. Skipped if NULL. @@ -227,20 +242,52 @@ typedef enum JobCreateFlags { JOB_MANUAL_DISMISS =3D 0x04, } JobCreateFlags; =20 +/** + * Allocate and return a new job transaction. Jobs can be added to the + * transaction using job_txn_add_job(). + * + * The transaction is automatically freed when the last job completes or is + * cancelled. + * + * All jobs in the transaction either complete successfully or fail/cancel= as a + * group. Jobs wait for each other before completing. Cancelling one job + * cancels all jobs in the transaction. + */ +JobTxn *job_txn_new(void); + +/** + * Release a reference that was previously acquired with job_txn_add_job or + * job_txn_new. If it's the last reference to the object, it will be freed. + */ +void job_txn_unref(JobTxn *txn); + +/** + * @txn: The transaction (may be NULL) + * @job: Job to add to the transaction + * + * Add @job to the transaction. The @job must not already be in a transac= tion. + * The caller must call either block_job_txn_unref() or block_job_complete= d() + * to release the reference that is automatically grabbed here. + * + * If @txn is NULL, the function does nothing. + */ +void job_txn_add_job(JobTxn *txn, Job *job); =20 /** * 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. + * @txn: The transaction this job belongs to, if any. %NULL otherwise. * @ctx: The AioContext to run the job coroutine in. * @flags: Creation flags for the job. See @JobCreateFlags. * @cb: Completion function for the job. * @opaque: Opaque pointer value passed to @cb. * @errp: Error object. */ -void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, - int flags, BlockCompletionFunc *cb, void *opaque, Error *= *errp); +void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, + AioContext *ctx, int flags, BlockCompletionFunc *cb, + void *opaque, Error **errp); =20 /** * Add a reference to Job refcnt, it will be decreased with job_unref, and= then @@ -260,9 +307,6 @@ void job_event_cancelled(Job *job); /** To be called when a successfully completed job is finalised. */ void job_event_completed(Job *job); =20 -/** To be called when the job transitions to PENDING */ -void job_event_pending(Job *job); - /** * @job: A job that has not yet been started. * @@ -351,6 +395,16 @@ void job_early_fail(Job *job); /** Asynchronously complete the specified @job. */ void job_complete(Job *job, Error **errp);; =20 +/** + * For a @job that has finished its work and is pending awaiting explicit + * acknowledgement to commit its work, this will commit that work. + * + * FIXME: Make the below statement universally true: + * For jobs that support the manual workflow mode, all graph changes that = occur + * as a result will occur after this command and before a successful reply. + */ +void job_finalize(Job *job, Error **errp); + typedef void JobDeferToMainLoopFn(Job *job, void *opaque); =20 /** @@ -389,8 +443,8 @@ void job_resume(Job *job); void job_do_dismiss(Job *job); int job_finalize_single(Job *job); void job_update_rc(Job *job); - -typedef struct BlockJob BlockJob; -void block_job_txn_del_job(BlockJob *job); +void job_cancel_async(Job *job, bool force); +void job_completed_txn_abort(Job *job); +void job_completed_txn_success(Job *job); =20 #endif diff --git a/blockdev.c b/blockdev.c index 69471c62b3..ec05ad89ae 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2255,7 +2255,7 @@ void qmp_transaction(TransactionActionList *dev_list, */ props =3D get_transaction_properties(props); if (props->completion_mode !=3D ACTION_COMPLETION_MODE_INDIVIDUAL) { - block_job_txn =3D block_job_txn_new(); + block_job_txn =3D job_txn_new(); } =20 /* drain all i/o before any operations */ @@ -2314,7 +2314,7 @@ exit: if (!has_props) { qapi_free_TransactionProperties(props); } - block_job_txn_unref(block_job_txn); + job_txn_unref(block_job_txn); } =20 void qmp_eject(bool has_device, const char *device, @@ -3908,7 +3908,7 @@ void qmp_block_job_finalize(const char *id, Error **e= rrp) } =20 trace_qmp_block_job_finalize(job); - block_job_finalize(job, errp); + job_finalize(&job->job, errp); aio_context_release(aio_context); } =20 diff --git a/blockjob.c b/blockjob.c index 3afa0dbdca..b3d4c34e12 100644 --- a/blockjob.c +++ b/blockjob.c @@ -36,19 +36,6 @@ #include "qemu/coroutine.h" #include "qemu/timer.h" =20 -/* Transactional group of block jobs */ -struct JobTxn { - - /* Is this txn being cancelled? */ - bool aborting; - - /* List of jobs */ - QLIST_HEAD(, Job) jobs; - - /* Reference count */ - int refcnt; -}; - /* * The block job API is composed of two categories of functions. * @@ -95,48 +82,6 @@ BlockJob *block_job_get(const char *id) } } =20 -JobTxn *block_job_txn_new(void) -{ - JobTxn *txn =3D g_new0(JobTxn, 1); - QLIST_INIT(&txn->jobs); - txn->refcnt =3D 1; - return txn; -} - -static void block_job_txn_ref(JobTxn *txn) -{ - txn->refcnt++; -} - -void block_job_txn_unref(JobTxn *txn) -{ - if (txn && --txn->refcnt =3D=3D 0) { - g_free(txn); - } -} - -void block_job_txn_add_job(JobTxn *txn, BlockJob *job) -{ - if (!txn) { - return; - } - - assert(!job->txn); - job->txn =3D txn; - - QLIST_INSERT_HEAD(&txn->jobs, &job->job, txn_list); - block_job_txn_ref(txn); -} - -void block_job_txn_del_job(BlockJob *job) -{ - if (job->txn) { - QLIST_REMOVE(&job->job, txn_list); - block_job_txn_unref(job->txn); - job->txn =3D NULL; - } -} - static void block_job_attached_aio_context(AioContext *new_context, void *opaque); static void block_job_detach_aio_context(void *opaque); @@ -146,8 +91,6 @@ void block_job_free(Job *job) BlockJob *bjob =3D container_of(job, BlockJob, job); BlockDriverState *bs =3D blk_bs(bjob->blk); =20 - assert(!bjob->txn); - bs->job =3D NULL; block_job_remove_all_bdrv(bjob); blk_remove_aio_context_notifier(bjob->blk, @@ -262,158 +205,6 @@ const BlockJobDriver *block_job_driver(BlockJob *job) return job->driver; } =20 -static int block_job_prepare(BlockJob *job) -{ - if (job->job.ret =3D=3D 0 && job->driver->prepare) { - job->job.ret =3D job->driver->prepare(job); - } - return job->job.ret; -} - -static void job_cancel_async(Job *job, bool force) -{ - if (job->user_paused) { - /* Do not call job_enter here, the caller will handle it. */ - job->user_paused =3D false; - if (job->driver->user_resume) { - job->driver->user_resume(job); - } - assert(job->pause_count > 0); - job->pause_count--; - } - job->cancelled =3D true; - /* To prevent 'force =3D=3D false' overriding a previous 'force =3D=3D= true' */ - job->force_cancel |=3D force; -} - -static int block_job_txn_apply(JobTxn *txn, int fn(BlockJob *), bool lock) -{ - AioContext *ctx; - Job *job, *next; - BlockJob *bjob; - int rc =3D 0; - - QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { - assert(is_block_job(job)); - bjob =3D container_of(job, BlockJob, job); - - if (lock) { - ctx =3D job->aio_context; - aio_context_acquire(ctx); - } - rc =3D fn(bjob); - if (lock) { - aio_context_release(ctx); - } - if (rc) { - break; - } - } - return rc; -} - -static void block_job_completed_txn_abort(BlockJob *job) -{ - AioContext *ctx; - JobTxn *txn =3D job->txn; - Job *other_job; - - if (txn->aborting) { - /* - * We are cancelled by another job, which will handle everything. - */ - return; - } - txn->aborting =3D true; - block_job_txn_ref(txn); - - /* We are the first failed job. Cancel other jobs. */ - QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - ctx =3D other_job->aio_context; - aio_context_acquire(ctx); - } - - /* Other jobs are effectively cancelled by us, set the status for - * them; this job, however, may or may not be cancelled, depending - * on the caller, so leave it. */ - QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - if (other_job !=3D &job->job) { - job_cancel_async(other_job, false); - } - } - while (!QLIST_EMPTY(&txn->jobs)) { - other_job =3D QLIST_FIRST(&txn->jobs); - ctx =3D other_job->aio_context; - if (!job_is_completed(other_job)) { - assert(job_is_cancelled(other_job)); - job_finish_sync(other_job, NULL, NULL); - } - job_finalize_single(other_job); - aio_context_release(ctx); - } - - block_job_txn_unref(txn); -} - -static int block_job_needs_finalize(BlockJob *job) -{ - return !job->job.auto_finalize; -} - -static int block_job_finalize_single(BlockJob *job) -{ - return job_finalize_single(&job->job); -} - -static void block_job_do_finalize(BlockJob *job) -{ - int rc; - assert(job && job->txn); - - /* prepare the transaction to complete */ - rc =3D block_job_txn_apply(job->txn, block_job_prepare, true); - if (rc) { - block_job_completed_txn_abort(job); - } else { - block_job_txn_apply(job->txn, block_job_finalize_single, true); - } -} - -static int block_job_transition_to_pending(BlockJob *job) -{ - job_state_transition(&job->job, JOB_STATUS_PENDING); - if (!job->job.auto_finalize) { - job_event_pending(&job->job); - } - return 0; -} - -static void block_job_completed_txn_success(BlockJob *job) -{ - JobTxn *txn =3D job->txn; - Job *other_job; - - job_state_transition(&job->job, JOB_STATUS_WAITING); - - /* - * Successful completion, see if there are other running jobs in this - * txn. - */ - QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - if (!job_is_completed(other_job)) { - return; - } - assert(other_job->ret =3D=3D 0); - } - - block_job_txn_apply(txn, block_job_transition_to_pending, false); - - /* If no jobs need manual finalization, automatically do so */ - if (block_job_txn_apply(txn, block_job_needs_finalize, false) =3D=3D 0= ) { - block_job_do_finalize(job); - } -} - /* Assumes the block_job_mutex is held */ static bool job_timer_pending(Job *job) { @@ -452,15 +243,6 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, u= int64_t n) return ratelimit_calculate_delay(&job->limit, n); } =20 -void block_job_finalize(BlockJob *job, Error **errp) -{ - assert(job && job->job.id && job->txn); - if (job_apply_verb(&job->job, JOB_VERB_FINALIZE, errp)) { - return; - } - block_job_do_finalize(job); -} - void block_job_dismiss(BlockJob **jobptr, Error **errp) { BlockJob *job =3D *jobptr; @@ -484,7 +266,7 @@ void block_job_cancel(BlockJob *job, bool force) if (!job_started(&job->job)) { block_job_completed(job, -ECANCELED); } else if (job->job.deferred_to_main_loop) { - block_job_completed_txn_abort(job); + job_completed_txn_abort(&job->job); } else { block_job_enter(job); } @@ -655,7 +437,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, return NULL; } =20 - job =3D job_create(job_id, &driver->job_driver, blk_get_aio_context(bl= k), + job =3D job_create(job_id, &driver->job_driver, txn, blk_get_aio_conte= xt(blk), flags, cb, opaque, errp); if (job =3D=3D NULL) { blk_unref(blk); @@ -703,30 +485,20 @@ void *block_job_create(const char *job_id, const Bloc= kJobDriver *driver, } } =20 - /* Single jobs are modeled as single-job transactions for sake of - * consolidating the job management logic */ - if (!txn) { - txn =3D block_job_txn_new(); - block_job_txn_add_job(txn, job); - block_job_txn_unref(txn); - } else { - block_job_txn_add_job(txn, job); - } - return job; } =20 void block_job_completed(BlockJob *job, int ret) { - assert(job && job->txn && !job_is_completed(&job->job)); + assert(job && job->job.txn && !job_is_completed(&job->job)); assert(blk_bs(job->blk)->job =3D=3D job); job->job.ret =3D ret; job_update_rc(&job->job); trace_block_job_completed(job, ret, job->job.ret); if (job->job.ret) { - block_job_completed_txn_abort(job); + job_completed_txn_abort(&job->job); } else { - block_job_completed_txn_success(job); + job_completed_txn_success(&job->job); } } =20 diff --git a/job.c b/job.c index db3d8536f7..f2381b559c 100644 --- a/job.c +++ b/job.c @@ -63,6 +63,19 @@ bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] =3D { [JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, }; =20 +/* Transactional group of jobs */ +struct JobTxn { + + /* Is this txn being cancelled? */ + bool aborting; + + /* List of jobs */ + QLIST_HEAD(, Job) jobs; + + /* Reference count */ + int refcnt; +}; + /* Right now, this mutex is only needed to synchronize accesses to job->bu= sy * and job->sleep_timer, such as concurrent calls to job_do_yield and * job_enter. */ @@ -83,6 +96,71 @@ static void __attribute__((__constructor__)) job_init(vo= id) qemu_mutex_init(&job_mutex); } =20 +JobTxn *job_txn_new(void) +{ + JobTxn *txn =3D g_new0(JobTxn, 1); + QLIST_INIT(&txn->jobs); + txn->refcnt =3D 1; + return txn; +} + +static void job_txn_ref(JobTxn *txn) +{ + txn->refcnt++; +} + +void job_txn_unref(JobTxn *txn) +{ + if (txn && --txn->refcnt =3D=3D 0) { + g_free(txn); + } +} + +void job_txn_add_job(JobTxn *txn, Job *job) +{ + if (!txn) { + return; + } + + assert(!job->txn); + job->txn =3D txn; + + QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); + job_txn_ref(txn); +} + +static void job_txn_del_job(Job *job) +{ + if (job->txn) { + QLIST_REMOVE(job, txn_list); + job_txn_unref(job->txn); + job->txn =3D NULL; + } +} + +static int job_txn_apply(JobTxn *txn, int fn(Job *), bool lock) +{ + AioContext *ctx; + Job *job, *next; + int rc =3D 0; + + QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { + if (lock) { + ctx =3D job->aio_context; + aio_context_acquire(ctx); + } + rc =3D fn(job); + if (lock) { + aio_context_release(ctx); + } + if (rc) { + break; + } + } + return rc; +} + + /* TODO Make static once the whole state machine is in job.c */ void job_state_transition(Job *job, JobStatus s1) { @@ -185,8 +263,9 @@ static void job_sleep_timer_cb(void *opaque) job_enter(job); } =20 -void *job_create(const char *job_id, const JobDriver *driver, AioContext *= ctx, - int flags, BlockCompletionFunc *cb, void *opaque, Error *= *errp) +void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, + AioContext *ctx, int flags, BlockCompletionFunc *cb, + void *opaque, Error **errp) { Job *job; =20 @@ -232,6 +311,16 @@ void *job_create(const char *job_id, const JobDriver *= driver, AioContext *ctx, =20 QLIST_INSERT_HEAD(&jobs, job, job_list); =20 + /* Single jobs are modeled as single-job transactions for sake of + * consolidating the job management logic */ + if (!txn) { + txn =3D job_txn_new(); + job_txn_add_job(txn, job); + job_txn_unref(txn); + } else { + job_txn_add_job(txn, job); + } + return job; } =20 @@ -245,6 +334,7 @@ void job_unref(Job *job) if (--job->refcnt =3D=3D 0) { assert(job->status =3D=3D JOB_STATUS_NULL); assert(!timer_pending(&job->sleep_timer)); + assert(!job->txn); =20 if (job->driver->free) { job->driver->free(job); @@ -267,9 +357,10 @@ void job_event_completed(Job *job) notifier_list_notify(&job->on_finalize_completed, job); } =20 -void job_event_pending(Job *job) +static int job_event_pending(Job *job) { notifier_list_notify(&job->on_pending, job); + return 0; } =20 /* @@ -469,8 +560,7 @@ void job_do_dismiss(Job *job) job->paused =3D false; job->deferred_to_main_loop =3D true; =20 - /* TODO Don't assume it's a BlockJob */ - block_job_txn_del_job((BlockJob*) job); + job_txn_del_job(job); =20 job_state_transition(job, JOB_STATUS_NULL); job_unref(job); @@ -550,12 +640,141 @@ int job_finalize_single(Job *job) } } =20 - /* TODO Don't assume it's a BlockJob */ - block_job_txn_del_job((BlockJob*) job); + job_txn_del_job(job); job_conclude(job); return 0; } =20 +void job_cancel_async(Job *job, bool force) +{ + if (job->user_paused) { + /* Do not call job_enter here, the caller will handle it. */ + job->user_paused =3D false; + if (job->driver->user_resume) { + job->driver->user_resume(job); + } + assert(job->pause_count > 0); + job->pause_count--; + } + job->cancelled =3D true; + /* To prevent 'force =3D=3D false' overriding a previous 'force =3D=3D= true' */ + job->force_cancel |=3D force; +} + +void job_completed_txn_abort(Job *job) +{ + AioContext *ctx; + JobTxn *txn =3D job->txn; + Job *other_job; + + if (txn->aborting) { + /* + * We are cancelled by another job, which will handle everything. + */ + return; + } + txn->aborting =3D true; + job_txn_ref(txn); + + /* We are the first failed job. Cancel other jobs. */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { + ctx =3D other_job->aio_context; + aio_context_acquire(ctx); + } + + /* Other jobs are effectively cancelled by us, set the status for + * them; this job, however, may or may not be cancelled, depending + * on the caller, so leave it. */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { + if (other_job !=3D job) { + job_cancel_async(other_job, false); + } + } + while (!QLIST_EMPTY(&txn->jobs)) { + other_job =3D QLIST_FIRST(&txn->jobs); + ctx =3D other_job->aio_context; + if (!job_is_completed(other_job)) { + assert(job_is_cancelled(other_job)); + job_finish_sync(other_job, NULL, NULL); + } + job_finalize_single(other_job); + aio_context_release(ctx); + } + + job_txn_unref(txn); +} + +static int job_prepare(Job *job) +{ + if (job->ret =3D=3D 0 && job->driver->prepare) { + job->ret =3D job->driver->prepare(job); + } + return job->ret; +} + +static int job_needs_finalize(Job *job) +{ + return !job->auto_finalize; +} + +static void job_do_finalize(Job *job) +{ + int rc; + assert(job && job->txn); + + /* prepare the transaction to complete */ + rc =3D job_txn_apply(job->txn, job_prepare, true); + if (rc) { + job_completed_txn_abort(job); + } else { + job_txn_apply(job->txn, job_finalize_single, true); + } +} + +void job_finalize(Job *job, Error **errp) +{ + assert(job && job->id && job->txn); + if (job_apply_verb(job, JOB_VERB_FINALIZE, errp)) { + return; + } + job_do_finalize(job); +} + +static int job_transition_to_pending(Job *job) +{ + job_state_transition(job, JOB_STATUS_PENDING); + if (!job->auto_finalize) { + job_event_pending(job); + } + return 0; +} + +void job_completed_txn_success(Job *job) +{ + JobTxn *txn =3D job->txn; + Job *other_job; + + job_state_transition(job, JOB_STATUS_WAITING); + + /* + * Successful completion, see if there are other running jobs in this + * txn. + */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { + if (!job_is_completed(other_job)) { + return; + } + assert(other_job->ret =3D=3D 0); + } + + job_txn_apply(txn, job_transition_to_pending, false); + + /* If no jobs need manual finalization, automatically do so */ + if (job_txn_apply(txn, job_needs_finalize, false) =3D=3D 0) { + job_do_finalize(job); + } +} + void job_complete(Job *job, Error **errp) { /* Should not be reachable via external interface for internal jobs */ diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index ec5d592b68..6ee31d59ad 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -125,7 +125,7 @@ static void test_single_job(int expected) JobTxn *txn; int result =3D -EINPROGRESS; =20 - txn =3D block_job_txn_new(); + txn =3D job_txn_new(); job =3D test_block_job_start(1, true, expected, &result, txn); job_start(&job->job); =20 @@ -138,7 +138,7 @@ static void test_single_job(int expected) } g_assert_cmpint(result, =3D=3D, expected); =20 - block_job_txn_unref(txn); + job_txn_unref(txn); } =20 static void test_single_job_success(void) @@ -164,7 +164,7 @@ static void test_pair_jobs(int expected1, int expected2) int result1 =3D -EINPROGRESS; int result2 =3D -EINPROGRESS; =20 - txn =3D block_job_txn_new(); + txn =3D job_txn_new(); job1 =3D test_block_job_start(1, true, expected1, &result1, txn); job2 =3D test_block_job_start(2, true, expected2, &result2, txn); job_start(&job1->job); @@ -173,7 +173,7 @@ static void test_pair_jobs(int expected1, int expected2) /* Release our reference now to trigger as many nice * use-after-free bugs as possible. */ - block_job_txn_unref(txn); + job_txn_unref(txn); =20 if (expected1 =3D=3D -ECANCELED) { block_job_cancel(job1, false); @@ -226,7 +226,7 @@ static void test_pair_jobs_fail_cancel_race(void) int result1 =3D -EINPROGRESS; int result2 =3D -EINPROGRESS; =20 - txn =3D block_job_txn_new(); + txn =3D job_txn_new(); job1 =3D test_block_job_start(1, true, -ECANCELED, &result1, txn); job2 =3D test_block_job_start(2, false, 0, &result2, txn); job_start(&job1->job); @@ -247,7 +247,7 @@ static void test_pair_jobs_fail_cancel_race(void) g_assert_cmpint(result1, =3D=3D, -ECANCELED); g_assert_cmpint(result2, =3D=3D, -ECANCELED); =20 - block_job_txn_unref(txn); + job_txn_unref(txn); } =20 int main(int argc, char **argv) diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index e44c608327..1e052c2e9c 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -364,7 +364,7 @@ static void test_cancel_concluded(void) } assert(job->job.status =3D=3D JOB_STATUS_PENDING); =20 - block_job_finalize(job, &error_abort); + job_finalize(&job->job, &error_abort); assert(job->job.status =3D=3D JOB_STATUS_CONCLUDED); =20 cancel_common(s); --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152458700089526.158717164793984; Tue, 24 Apr 2018 09:23:20 -0700 (PDT) Received: from localhost ([::1]:59458 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0ir-0003Nq-OH for importer@patchew.org; Tue, 24 Apr 2018 12:23:17 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48308) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpe-000051-2u for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpb-0000KA-Bv for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:14 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:58906 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpU-00006K-Br; Tue, 24 Apr 2018 11:26:04 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DB787401DE60; Tue, 24 Apr 2018 15:26:03 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id CC5F8202342F; Tue, 24 Apr 2018 15:26:02 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:13 +0200 Message-Id: <20180424152515.25664-32-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 24 Apr 2018 15:26:03 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 24 Apr 2018 15:26:03 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 31/33] job: Move completion and cancellation to Job X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves the top-level job completion and cancellation functions from BlockJob to Job. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 55 -------------------------------- include/block/blockjob_int.h | 18 ----------- include/qemu/job.h | 53 +++++++++++++++++++++++++++++- block.c | 2 +- block/backup.c | 3 +- block/commit.c | 8 ++--- block/mirror.c | 6 ++-- block/replication.c | 4 +-- block/stream.c | 2 +- blockdev.c | 8 ++--- blockjob.c | 76 ----------------------------------------= ---- job.c | 68 +++++++++++++++++++++++++++++++++++++++ qemu-img.c | 2 +- tests/test-bdrv-drain.c | 5 ++- tests/test-blockjob-txn.c | 14 ++++---- tests/test-blockjob.c | 21 ++++++------ block/trace-events | 3 -- trace-events | 1 + 18 files changed, 157 insertions(+), 192 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index e8e9e5f370..7a0d95e789 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -141,15 +141,6 @@ void block_job_remove_all_bdrv(BlockJob *job); void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); =20 /** - * block_job_cancel: - * @job: The job to be canceled. - * @force: Quit a job without waiting for data to be in sync. - * - * Asynchronously cancel the specified job. - */ -void block_job_cancel(BlockJob *job, bool force); - -/** * block_job_dismiss: * @job: The job to be dismissed. * @errp: Error object. @@ -186,52 +177,6 @@ void block_job_progress_set_remaining(BlockJob *job, u= int64_t remaining); BlockJobInfo *block_job_query(BlockJob *job, Error **errp); =20 /** - * block_job_user_cancel: - * @job: The job to be cancelled. - * @force: Quit a job without waiting for data to be in sync. - * - * Cancels the specified job, but may refuse to do so if the - * operation isn't currently meaningful. - */ -void block_job_user_cancel(BlockJob *job, bool force, Error **errp); - -/** - * block_job_cancel_sync: - * @job: The job to be canceled. - * - * Synchronously cancel the job. The completion callback is called - * before the function returns. The job may actually complete - * instead of canceling itself; the circumstances under which this - * happens depend on the kind of job that is active. - * - * Returns the return value from the job if the job actually completed - * during the call, or -ECANCELED if it was canceled. - */ -int block_job_cancel_sync(BlockJob *job); - -/** - * block_job_cancel_sync_all: - * - * Synchronously cancels all jobs using block_job_cancel_sync(). - */ -void block_job_cancel_sync_all(void); - -/** - * block_job_complete_sync: - * @job: The job to be completed. - * @errp: Error object which may be set by block_job_complete(); this is n= ot - * necessarily set on every error, the job return value has to be - * checked as well. - * - * Synchronously complete the job. The completion callback is called befo= re the - * function returns, unless it is NULL (which is permissible when using th= is - * function). - * - * Returns the return value from the job. - */ -int block_job_complete_sync(BlockJob *job, Error **errp); - -/** * block_job_iostatus_reset: * @job: The job whose I/O status should be reset. * diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 2519b1f879..2fdf35a9fd 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -124,24 +124,6 @@ void block_job_yield(BlockJob *job); int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n); =20 /** - * block_job_completed: - * @job: The job being completed. - * @ret: The status code. - * - * Call the completion function that was registered at creation time, and - * free @job. - */ -void block_job_completed(BlockJob *job, int ret); - -/** - * block_job_enter: - * @job: The job to enter. - * - * Continue the specified job by entering the coroutine. - */ -void block_job_enter(BlockJob *job); - -/** * block_job_event_ready: * @job: The job which is now ready to be completed. * diff --git a/include/qemu/job.h b/include/qemu/job.h index fceb18c6c7..9df0f5560b 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -392,8 +392,59 @@ Job *job_get(const char *id); /** The @job could not be started, free it. */ void job_early_fail(Job *job); =20 +/** + * @job: The job being completed. + * @ret: The status code. + * + * Marks @job as completed. If @ret is non-zero, the job transaction it is= part + * of is aborted. If @ret is zero, the job moves into the WAITING state. I= f it + * is the last job to complete in its transaction, all jobs in the transac= tion + * move from WAITING to PENDING. + */ +void job_completed(Job *job, int ret); + /** Asynchronously complete the specified @job. */ -void job_complete(Job *job, Error **errp);; +void job_complete(Job *job, Error **errp); + +/** + * Asynchronously cancel the specified @job. If @force is true, the job sh= ould + * be cancelled immediately without waiting for a consistent state. + */ +void job_cancel(Job *job, bool force); + +/** + * Cancels the specified job like job_cancel(), but may refuse to do so if= the + * operation isn't meaningful in the current state of the job. + */ +void job_user_cancel(Job *job, bool force, Error **errp); + +/** + * Synchronously cancel the @job. The completion callback is called + * before the function returns. The job may actually complete + * instead of canceling itself; the circumstances under which this + * happens depend on the kind of job that is active. + * + * Returns the return value from the job if the job actually completed + * during the call, or -ECANCELED if it was canceled. + */ +int job_cancel_sync(Job *job); + +/** Synchronously cancels all jobs using job_cancel_sync(). */ +void job_cancel_sync_all(void); + +/** + * @job: The job to be completed. + * @errp: Error object which may be set by job_complete(); this is not + * necessarily set on every error, the job return value has to be + * checked as well. + * + * Synchronously complete the job. The completion callback is called befo= re the + * function returns, unless it is NULL (which is permissible when using th= is + * function). + * + * Returns the return value from the job. + */ +int job_complete_sync(Job *job, Error **errp); =20 /** * For a @job that has finished its work and is pending awaiting explicit diff --git a/block.c b/block.c index a2caadf0a0..6352698367 100644 --- a/block.c +++ b/block.c @@ -3362,7 +3362,7 @@ static void bdrv_close(BlockDriverState *bs) =20 void bdrv_close_all(void) { - block_job_cancel_sync_all(); + job_cancel_sync_all(); nbd_export_close_all(); =20 /* Drop references from requests still in flight, such as canceled blo= ck diff --git a/block/backup.c b/block/backup.c index f83b14d8dc..ecc1e9164c 100644 --- a/block/backup.c +++ b/block/backup.c @@ -319,10 +319,9 @@ typedef struct { =20 static void backup_complete(Job *job, void *opaque) { - BlockJob *bjob =3D container_of(job, BlockJob, job); BackupCompleteData *data =3D opaque; =20 - block_job_completed(bjob, data->ret); + job_completed(job, data->ret); g_free(data); } =20 diff --git a/block/commit.c b/block/commit.c index 02a8af9127..56c3810bad 100644 --- a/block/commit.c +++ b/block/commit.c @@ -112,12 +112,12 @@ static void commit_complete(Job *job, void *opaque) blk_unref(s->top); =20 /* If there is more than one reference to the job (e.g. if called from - * block_job_finish_sync()), block_job_completed() won't free it and - * therefore the blockers on the intermediate nodes remain. This would - * cause bdrv_set_backing_hd() to fail. */ + * block_job_finish_sync()), job_completed() won't free it and therefo= re + * the blockers on the intermediate nodes remain. This would cause + * bdrv_set_backing_hd() to fail. */ block_job_remove_all_bdrv(bjob); =20 - block_job_completed(&s->common, ret); + job_completed(job, ret); g_free(data); =20 /* If bdrv_drop_intermediate() didn't already do that, remove the comm= it diff --git a/block/mirror.c b/block/mirror.c index 9eb5a21cd9..b722a407e1 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -498,7 +498,7 @@ static void mirror_exit(Job *job, void *opaque) bdrv_release_dirty_bitmap(src, s->dirty_bitmap); =20 /* Make sure that the source BDS doesn't go away before we called - * block_job_completed(). */ + * job_completed(). */ bdrv_ref(src); bdrv_ref(mirror_top_bs); bdrv_ref(target_bs); @@ -581,7 +581,7 @@ static void mirror_exit(Job *job, void *opaque) blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort); =20 - block_job_completed(&s->common, data->ret); + job_completed(job, data->ret); =20 g_free(data); bdrv_drained_end(src); @@ -950,7 +950,7 @@ static void mirror_complete(Job *job, Error **errp) } =20 s->should_complete =3D true; - block_job_enter(&s->common); + job_enter(job); } =20 static void mirror_pause(Job *job) diff --git a/block/replication.c b/block/replication.c index 8241400155..f3b2839531 100644 --- a/block/replication.c +++ b/block/replication.c @@ -145,7 +145,7 @@ static void replication_close(BlockDriverState *bs) replication_stop(s->rs, false, NULL); } if (s->stage =3D=3D BLOCK_REPLICATION_FAILOVER) { - block_job_cancel_sync(s->active_disk->bs->job); + job_cancel_sync(&s->active_disk->bs->job->job); } =20 if (s->mode =3D=3D REPLICATION_MODE_SECONDARY) { @@ -679,7 +679,7 @@ static void replication_stop(ReplicationState *rs, bool= failover, Error **errp) * disk, secondary disk in backup_job_completed(). */ if (s->secondary_disk->bs->job) { - block_job_cancel_sync(s->secondary_disk->bs->job); + job_cancel_sync(&s->secondary_disk->bs->job->job); } =20 if (!failover) { diff --git a/block/stream.c b/block/stream.c index b996278ab3..8546c412cd 100644 --- a/block/stream.c +++ b/block/stream.c @@ -93,7 +93,7 @@ out: } =20 g_free(s->backing_file_str); - block_job_completed(&s->common, data->ret); + job_completed(job, data->ret); g_free(data); } =20 diff --git a/blockdev.c b/blockdev.c index ec05ad89ae..c3e5f6a804 100644 --- a/blockdev.c +++ b/blockdev.c @@ -150,7 +150,7 @@ void blockdev_mark_auto_del(BlockBackend *blk) aio_context_acquire(aio_context); =20 if (bs->job) { - block_job_cancel(bs->job, false); + job_cancel(&bs->job->job, false); } =20 aio_context_release(aio_context); @@ -1925,7 +1925,7 @@ static void drive_backup_abort(BlkActionState *common) aio_context =3D bdrv_get_aio_context(state->bs); aio_context_acquire(aio_context); =20 - block_job_cancel_sync(state->job); + job_cancel_sync(&state->job->job); =20 aio_context_release(aio_context); } @@ -2023,7 +2023,7 @@ static void blockdev_backup_abort(BlkActionState *com= mon) aio_context =3D bdrv_get_aio_context(state->bs); aio_context_acquire(aio_context); =20 - block_job_cancel_sync(state->job); + job_cancel_sync(&state->job->job); =20 aio_context_release(aio_context); } @@ -3851,7 +3851,7 @@ void qmp_block_job_cancel(const char *device, } =20 trace_qmp_block_job_cancel(job); - block_job_user_cancel(job, force, errp); + job_user_cancel(&job->job, force, errp); out: aio_context_release(aio_context); } diff --git a/blockjob.c b/blockjob.c index b3d4c34e12..0cbe655c0e 100644 --- a/blockjob.c +++ b/blockjob.c @@ -256,63 +256,6 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) *jobptr =3D NULL; } =20 -void block_job_cancel(BlockJob *job, bool force) -{ - if (job->job.status =3D=3D JOB_STATUS_CONCLUDED) { - job_do_dismiss(&job->job); - return; - } - job_cancel_async(&job->job, force); - if (!job_started(&job->job)) { - block_job_completed(job, -ECANCELED); - } else if (job->job.deferred_to_main_loop) { - job_completed_txn_abort(&job->job); - } else { - block_job_enter(job); - } -} - -void block_job_user_cancel(BlockJob *job, bool force, Error **errp) -{ - if (job_apply_verb(&job->job, JOB_VERB_CANCEL, errp)) { - return; - } - block_job_cancel(job, force); -} - -/* A wrapper around block_job_cancel() taking an Error ** parameter so it = may be - * used with job_finish_sync() without the need for (rather nasty) function - * pointer casts there. */ -static void block_job_cancel_err(Job *job, Error **errp) -{ - BlockJob *bjob =3D container_of(job, BlockJob, job); - assert(is_block_job(job)); - block_job_cancel(bjob, false); -} - -int block_job_cancel_sync(BlockJob *job) -{ - return job_finish_sync(&job->job, &block_job_cancel_err, NULL); -} - -void block_job_cancel_sync_all(void) -{ - BlockJob *job; - AioContext *aio_context; - - while ((job =3D block_job_next(NULL))) { - aio_context =3D blk_get_aio_context(job->blk); - aio_context_acquire(aio_context); - block_job_cancel_sync(job); - aio_context_release(aio_context); - } -} - -int block_job_complete_sync(BlockJob *job, Error **errp) -{ - return job_finish_sync(&job->job, job_complete, errp); -} - void block_job_progress_update(BlockJob *job, uint64_t done) { job->offset +=3D done; @@ -488,25 +431,6 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, return job; } =20 -void block_job_completed(BlockJob *job, int ret) -{ - assert(job && job->job.txn && !job_is_completed(&job->job)); - assert(blk_bs(job->blk)->job =3D=3D job); - job->job.ret =3D ret; - job_update_rc(&job->job); - trace_block_job_completed(job, ret, job->job.ret); - if (job->job.ret) { - job_completed_txn_abort(&job->job); - } else { - job_completed_txn_success(&job->job); - } -} - -void block_job_enter(BlockJob *job) -{ - job_enter_cond(&job->job, NULL); -} - void block_job_yield(BlockJob *job) { assert(job->job.busy); diff --git a/job.c b/job.c index f2381b559c..20c901f7a9 100644 --- a/job.c +++ b/job.c @@ -775,6 +775,74 @@ void job_completed_txn_success(Job *job) } } =20 +void job_completed(Job *job, int ret) +{ + assert(job && job->txn && !job_is_completed(job)); + job->ret =3D ret; + job_update_rc(job); + trace_job_completed(job, ret, job->ret); + if (job->ret) { + job_completed_txn_abort(job); + } else { + job_completed_txn_success(job); + } +} + +void job_cancel(Job *job, bool force) +{ + if (job->status =3D=3D JOB_STATUS_CONCLUDED) { + job_do_dismiss(job); + return; + } + job_cancel_async(job, force); + if (!job_started(job)) { + job_completed(job, -ECANCELED); + } else if (job->deferred_to_main_loop) { + job_completed_txn_abort(job); + } else { + job_enter(job); + } +} + +void job_user_cancel(Job *job, bool force, Error **errp) +{ + if (job_apply_verb(job, JOB_VERB_CANCEL, errp)) { + return; + } + job_cancel(job, force); +} + +/* A wrapper around job_cancel() taking an Error ** parameter so it may be + * used with job_finish_sync() without the need for (rather nasty) function + * pointer casts there. */ +static void job_cancel_err(Job *job, Error **errp) +{ + job_cancel(job, false); +} + +int job_cancel_sync(Job *job) +{ + return job_finish_sync(job, &job_cancel_err, NULL); +} + +void job_cancel_sync_all(void) +{ + Job *job; + AioContext *aio_context; + + while ((job =3D job_next(NULL))) { + aio_context =3D job->aio_context; + aio_context_acquire(aio_context); + job_cancel_sync(job); + aio_context_release(aio_context); + } +} + +int job_complete_sync(Job *job, Error **errp) +{ + return job_finish_sync(job, job_complete, errp); +} + void job_complete(Job *job, Error **errp) { /* Should not be reachable via external interface for internal jobs */ diff --git a/qemu-img.c b/qemu-img.c index 4888064beb..75b03ee49c 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -870,7 +870,7 @@ static void run_block_job(BlockJob *job, Error **errp) } while (!job->ready && !job_is_completed(&job->job)); =20 if (!job_is_completed(&job->job)) { - ret =3D block_job_complete_sync(job, errp); + ret =3D job_complete_sync(&job->job, errp); } else { ret =3D job->job.ret; } diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index b428aaca68..3600ffd3fb 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -498,8 +498,7 @@ typedef struct TestBlockJob { =20 static void test_job_completed(Job *job, void *opaque) { - BlockJob *bjob =3D container_of(job, BlockJob, job); - block_job_completed(bjob, 0); + job_completed(job, 0); } =20 static void coroutine_fn test_job_start(void *opaque) @@ -593,7 +592,7 @@ static void test_blockjob_common(enum drain_type drain_= type) g_assert_false(job->job.paused); g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ =20 - ret =3D block_job_complete_sync(job, &error_abort); + ret =3D job_complete_sync(&job->job, &error_abort); g_assert_cmpint(ret, =3D=3D, 0); =20 blk_unref(blk_src); diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 6ee31d59ad..34ee179574 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -34,7 +34,7 @@ static void test_block_job_complete(Job *job, void *opaqu= e) rc =3D -ECANCELED; } =20 - block_job_completed(bjob, rc); + job_completed(job, rc); bdrv_unref(bs); } =20 @@ -130,7 +130,7 @@ static void test_single_job(int expected) job_start(&job->job); =20 if (expected =3D=3D -ECANCELED) { - block_job_cancel(job, false); + job_cancel(&job->job, false); } =20 while (result =3D=3D -EINPROGRESS) { @@ -176,10 +176,10 @@ static void test_pair_jobs(int expected1, int expecte= d2) job_txn_unref(txn); =20 if (expected1 =3D=3D -ECANCELED) { - block_job_cancel(job1, false); + job_cancel(&job1->job, false); } if (expected2 =3D=3D -ECANCELED) { - block_job_cancel(job2, false); + job_cancel(&job2->job, false); } =20 while (result1 =3D=3D -EINPROGRESS || result2 =3D=3D -EINPROGRESS) { @@ -232,13 +232,13 @@ static void test_pair_jobs_fail_cancel_race(void) job_start(&job1->job); job_start(&job2->job); =20 - block_job_cancel(job1, false); + job_cancel(&job1->job, false); =20 /* Now make job2 finish before the main loop kicks jobs. This simulat= es * the race between a pending kick and another job completing. */ - block_job_enter(job2); - block_job_enter(job2); + job_enter(&job2->job); + job_enter(&job2->job); =20 while (result1 =3D=3D -EINPROGRESS || result2 =3D=3D -EINPROGRESS) { aio_poll(qemu_get_aio_context(), true); diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 1e052c2e9c..46a78739aa 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -165,10 +165,9 @@ typedef struct CancelJob { =20 static void cancel_job_completed(Job *job, void *opaque) { - BlockJob *bjob =3D container_of(job, BlockJob, job); CancelJob *s =3D opaque; s->completed =3D true; - block_job_completed(bjob, 0); + job_completed(job, 0); } =20 static void cancel_job_complete(Job *job, Error **errp) @@ -232,7 +231,7 @@ static void cancel_common(CancelJob *s) BlockBackend *blk =3D s->blk; JobStatus sts =3D job->job.status; =20 - block_job_cancel_sync(job); + job_cancel_sync(&job->job); if (sts !=3D JOB_STATUS_CREATED && sts !=3D JOB_STATUS_CONCLUDED) { BlockJob *dummy =3D job; block_job_dismiss(&dummy, &error_abort); @@ -275,7 +274,7 @@ static void test_cancel_paused(void) assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 job_user_pause(&job->job, &error_abort); - block_job_enter(job); + job_enter(&job->job); assert(job->job.status =3D=3D JOB_STATUS_PAUSED); =20 cancel_common(s); @@ -292,7 +291,7 @@ static void test_cancel_ready(void) assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; - block_job_enter(job); + job_enter(&job->job); assert(job->job.status =3D=3D JOB_STATUS_READY); =20 cancel_common(s); @@ -309,11 +308,11 @@ static void test_cancel_standby(void) assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; - block_job_enter(job); + job_enter(&job->job); assert(job->job.status =3D=3D JOB_STATUS_READY); =20 job_user_pause(&job->job, &error_abort); - block_job_enter(job); + job_enter(&job->job); assert(job->job.status =3D=3D JOB_STATUS_STANDBY); =20 cancel_common(s); @@ -330,11 +329,11 @@ static void test_cancel_pending(void) assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; - block_job_enter(job); + job_enter(&job->job); assert(job->job.status =3D=3D JOB_STATUS_READY); =20 job_complete(&job->job, &error_abort); - block_job_enter(job); + job_enter(&job->job); while (!s->completed) { aio_poll(qemu_get_aio_context(), true); } @@ -354,11 +353,11 @@ static void test_cancel_concluded(void) assert(job->job.status =3D=3D JOB_STATUS_RUNNING); =20 s->should_converge =3D true; - block_job_enter(job); + job_enter(&job->job); assert(job->job.status =3D=3D JOB_STATUS_READY); =20 job_complete(&job->job, &error_abort); - block_job_enter(job); + job_enter(&job->job); while (!s->completed) { aio_poll(qemu_get_aio_context(), true); } diff --git a/block/trace-events b/block/trace-events index 93b927908a..2d59b53fd3 100644 --- a/block/trace-events +++ b/block/trace-events @@ -4,9 +4,6 @@ bdrv_open_common(void *bs, const char *filename, int flags, const char *fo= rmat_name) "bs %p filename \"%s\" flags 0x%x format_name \"%s\"" bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" =20 -# blockjob.c -block_job_completed(void *job, int ret, int jret) "job %p ret %d corrected= ret %d" - # block/block-backend.c blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int= flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x" blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, in= t flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x" diff --git a/trace-events b/trace-events index 2507e1327d..ef7579a285 100644 --- a/trace-events +++ b/trace-events @@ -107,6 +107,7 @@ gdbstub_err_checksum_incorrect(uint8_t expected, uint8_= t got) "got command packe # job.c job_state_transition(void *job, int ret, const char *legal, const char *s= 0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" job_apply_verb(void *job, const char *state, const char *verb, const char = *legal) "job %p in state %s; applying verb %s (%s)" +job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %= d" =20 ### Guest events, keep at bottom =20 --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524585590076660.5282939040201; Tue, 24 Apr 2018 08:59:50 -0700 (PDT) Received: from localhost ([::1]:59295 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB0M9-0001hS-9u for importer@patchew.org; Tue, 24 Apr 2018 11:59:49 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48283) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpc-0008VT-Ur for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpb-0000Kj-Kr for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:12 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45640 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpV-00008f-Hx; Tue, 24 Apr 2018 11:26:05 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 329144270947; Tue, 24 Apr 2018 15:26:05 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 23269202323A; Tue, 24 Apr 2018 15:26:04 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:14 +0200 Message-Id: <20180424152515.25664-33-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:26:05 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 24 Apr 2018 15:26:05 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 32/33] job: Add job_yield() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves block_job_yield() to the Job layer. Signed-off-by: Kevin Wolf --- include/block/blockjob_int.h | 8 -------- include/qemu/job.h | 8 +++++++- block/backup.c | 2 +- block/mirror.c | 2 +- blockjob.c | 16 ---------------- job.c | 18 +++++++++++++++++- tests/test-blockjob-txn.c | 2 +- 7 files changed, 27 insertions(+), 29 deletions(-) diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 2fdf35a9fd..3f49ba5472 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -108,14 +108,6 @@ void block_job_user_resume(Job *job); void block_job_drain(Job *job); =20 /** - * block_job_yield: - * @job: The job that calls the function. - * - * Yield the block job coroutine. - */ -void block_job_yield(BlockJob *job); - -/** * block_job_ratelimit_get_delay: * * Calculate and return delay for the next request in ns. See the docuemnt= ation diff --git a/include/qemu/job.h b/include/qemu/job.h index 9df0f5560b..1a4d6167e6 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -332,6 +332,13 @@ void coroutine_fn job_pause_point(Job *job); =20 /** * @job: The job that calls the function. + * + * Yield the job coroutine. + */ +void job_yield(Job *job); + +/** + * @job: The job that calls the function. * @ns: How many nanoseconds to stop for. * * Put the job to sleep (assuming that it wasn't canceled) for @ns @@ -485,7 +492,6 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Err= or **errp), Error **errp) /* TODO To be removed from the public interface */ void job_state_transition(Job *job, JobStatus s1); int job_apply_verb(Job *job, JobVerb bv, Error **errp); -void coroutine_fn job_do_yield(Job *job, uint64_t ns); bool job_should_pause(Job *job); bool job_started(Job *job); void job_enter_cond(Job *job, bool(*fn)(Job *job)); diff --git a/block/backup.c b/block/backup.c index ecc1e9164c..3436a87a8e 100644 --- a/block/backup.c +++ b/block/backup.c @@ -444,7 +444,7 @@ static void coroutine_fn backup_run(void *opaque) while (!job_is_cancelled(&job->common.job)) { /* Yield until the job is cancelled. We just let our before_w= rite * notify callback service CoW requests. */ - block_job_yield(&job->common); + job_yield(&job->common.job); } } else if (job->sync_mode =3D=3D MIRROR_SYNC_MODE_INCREMENTAL) { ret =3D backup_run_incremental(job); diff --git a/block/mirror.c b/block/mirror.c index b722a407e1..669aca227d 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -731,7 +731,7 @@ static void coroutine_fn mirror_run(void *opaque) block_job_event_ready(&s->common); s->synced =3D true; while (!job_is_cancelled(&s->common.job) && !s->should_complete) { - block_job_yield(&s->common); + job_yield(&s->common.job); } s->common.job.cancelled =3D false; goto immediate_exit; diff --git a/blockjob.c b/blockjob.c index 0cbe655c0e..6569624691 100644 --- a/blockjob.c +++ b/blockjob.c @@ -431,22 +431,6 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, return job; } =20 -void block_job_yield(BlockJob *job) -{ - assert(job->job.busy); - - /* Check cancellation *before* setting busy =3D false, too! */ - if (job_is_cancelled(&job->job)) { - return; - } - - if (!job_should_pause(&job->job)) { - job_do_yield(&job->job, -1); - } - - job_pause_point(&job->job); -} - void block_job_iostatus_reset(BlockJob *job) { if (job->iostatus =3D=3D BLOCK_DEVICE_IO_STATUS_OK) { diff --git a/job.c b/job.c index 20c901f7a9..5bc98b9794 100644 --- a/job.c +++ b/job.c @@ -405,7 +405,7 @@ void job_enter(Job *job) * * If @ns is (uint64_t) -1, no timer is scheduled and block_job_enter() mu= st be * called explicitly. */ -void coroutine_fn job_do_yield(Job *job, uint64_t ns) +static void coroutine_fn job_do_yield(Job *job, uint64_t ns) { job_lock(); if (ns !=3D -1) { @@ -450,6 +450,22 @@ void coroutine_fn job_pause_point(Job *job) } } =20 +void job_yield(Job *job) +{ + assert(job->busy); + + /* Check cancellation *before* setting busy =3D false, too! */ + if (job_is_cancelled(job)) { + return; + } + + if (!job_should_pause(job)) { + job_do_yield(job, -1); + } + + job_pause_point(job); +} + void coroutine_fn job_sleep_ns(Job *job, int64_t ns) { assert(job->busy); diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 34ee179574..fce836639a 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -47,7 +47,7 @@ static void coroutine_fn test_block_job_run(void *opaque) if (s->use_timer) { job_sleep_ns(&job->job, 0); } else { - block_job_yield(job); + job_yield(&job->job); } =20 if (job_is_cancelled(&job->job)) { --=20 2.13.6 From nobody Wed Oct 29 06:51:52 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1524584827058759.7771096728162; Tue, 24 Apr 2018 08:47:07 -0700 (PDT) Received: from localhost ([::1]:59213 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fB09k-0007tF-Ug for importer@patchew.org; Tue, 24 Apr 2018 11:47:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48306) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fAzpd-0008WL-Rr for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fAzpc-0000Ln-MK for qemu-devel@nongnu.org; Tue, 24 Apr 2018 11:26:13 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34868 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fAzpW-0000Aq-SQ; Tue, 24 Apr 2018 11:26:06 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7DC53EC014; Tue, 24 Apr 2018 15:26:06 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-100.ams2.redhat.com [10.36.117.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6DF33202342F; Tue, 24 Apr 2018 15:26:05 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 24 Apr 2018 17:25:15 +0200 Message-Id: <20180424152515.25664-34-kwolf@redhat.com> In-Reply-To: <20180424152515.25664-1-kwolf@redhat.com> References: <20180424152515.25664-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:26:06 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 24 Apr 2018 15:26:06 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [RFC PATCH 33/33] job: Add job_dismiss() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, jcody@redhat.com, jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves block_job_dismiss() to the Job layer. Signed-off-by: Kevin Wolf --- include/block/blockjob.h | 9 --------- include/qemu/job.h | 6 ++++++ blockdev.c | 8 +++++--- blockjob.c | 13 ------------- job.c | 13 +++++++++++++ tests/test-blockjob.c | 4 ++-- 6 files changed, 26 insertions(+), 27 deletions(-) diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 7a0d95e789..ba08bcf7c0 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -141,15 +141,6 @@ void block_job_remove_all_bdrv(BlockJob *job); void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); =20 /** - * block_job_dismiss: - * @job: The job to be dismissed. - * @errp: Error object. - * - * Remove a concluded job from the query list. - */ -void block_job_dismiss(BlockJob **job, Error **errp); - -/** * block_job_progress_update: * @job: The job that has made progress * @done: How much progress the job made diff --git a/include/qemu/job.h b/include/qemu/job.h index 1a4d6167e6..f0af1db123 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -463,6 +463,12 @@ int job_complete_sync(Job *job, Error **errp); */ void job_finalize(Job *job, Error **errp); =20 +/** + * Remove the concluded @job from the query list and resets the passed poi= nter + * to %NULL. Returns an error if the job is not actually concluded. + */ +void job_dismiss(Job **job, Error **errp); + typedef void JobDeferToMainLoopFn(Job *job, void *opaque); =20 /** diff --git a/blockdev.c b/blockdev.c index c3e5f6a804..87993de5b7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3915,14 +3915,16 @@ void qmp_block_job_finalize(const char *id, Error *= *errp) void qmp_block_job_dismiss(const char *id, Error **errp) { AioContext *aio_context; - BlockJob *job =3D find_block_job(id, &aio_context, errp); + BlockJob *bjob =3D find_block_job(id, &aio_context, errp); + Job *job; =20 - if (!job) { + if (!bjob) { return; } =20 trace_qmp_block_job_dismiss(job); - block_job_dismiss(&job, errp); + job =3D &bjob->job; + job_dismiss(&job, errp); aio_context_release(aio_context); } =20 diff --git a/blockjob.c b/blockjob.c index 6569624691..87dfe10130 100644 --- a/blockjob.c +++ b/blockjob.c @@ -243,19 +243,6 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, u= int64_t n) return ratelimit_calculate_delay(&job->limit, n); } =20 -void block_job_dismiss(BlockJob **jobptr, Error **errp) -{ - BlockJob *job =3D *jobptr; - /* similarly to _complete, this is QMP-interface only. */ - assert(job->job.id); - if (job_apply_verb(&job->job, JOB_VERB_DISMISS, errp)) { - return; - } - - job_do_dismiss(&job->job); - *jobptr =3D NULL; -} - void block_job_progress_update(BlockJob *job, uint64_t done) { job->offset +=3D done; diff --git a/job.c b/job.c index 5bc98b9794..b8c89e3fec 100644 --- a/job.c +++ b/job.c @@ -582,6 +582,19 @@ void job_do_dismiss(Job *job) job_unref(job); } =20 +void job_dismiss(Job **jobptr, Error **errp) +{ + Job *job =3D *jobptr; + /* similarly to _complete, this is QMP-interface only. */ + assert(job->id); + if (job_apply_verb(job, JOB_VERB_DISMISS, errp)) { + return; + } + + job_do_dismiss(job); + *jobptr =3D NULL; +} + void job_early_fail(Job *job) { assert(job->status =3D=3D JOB_STATUS_CREATED); diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 46a78739aa..7131cabb16 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -233,8 +233,8 @@ static void cancel_common(CancelJob *s) =20 job_cancel_sync(&job->job); if (sts !=3D JOB_STATUS_CREATED && sts !=3D JOB_STATUS_CONCLUDED) { - BlockJob *dummy =3D job; - block_job_dismiss(&dummy, &error_abort); + Job *dummy =3D &job->job; + job_dismiss(&dummy, &error_abort); } assert(job->job.status =3D=3D JOB_STATUS_NULL); job_unref(&job->job); --=20 2.13.6