From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517018944913114.61429695849915; Fri, 26 Jan 2018 18:09:04 -0800 (PST) Received: from localhost ([::1]:43659 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFvR-0005BZ-Vh for importer@patchew.org; Fri, 26 Jan 2018 21:09:02 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37228) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs3-0000pK-8J for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:33 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs1-0008M8-5J for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:31 -0500 Received: from mx1.redhat.com ([209.132.183.28]:55506) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFrw-0008Hd-4z; Fri, 26 Jan 2018 21:05:24 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 78E8BC05FFE2; Sat, 27 Jan 2018 02:05:23 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id AC6495457C; Sat, 27 Jan 2018 02:05:22 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:02 -0500 Message-Id: <20180127020515.27137-2-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Sat, 27 Jan 2018 02:05:23 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 01/14] blockjobs: add manual property 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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 property will be used to opt-in to the new BlockJobs workflow that allows a tighter, more explicit control over transitions from one runstate to another. Signed-off-by: John Snow --- block/backup.c | 20 ++++++++++---------- block/commit.c | 2 +- block/mirror.c | 2 +- block/replication.c | 5 +++-- block/stream.c | 2 +- blockdev.c | 4 ++-- blockjob.c | 3 ++- include/block/block_int.h | 6 +++--- include/block/blockjob.h | 5 +++++ include/block/blockjob_int.h | 2 +- tests/test-bdrv-drain.c | 4 ++-- tests/test-blockjob-txn.c | 2 +- tests/test-blockjob.c | 4 ++-- 13 files changed, 34 insertions(+), 27 deletions(-) diff --git a/block/backup.c b/block/backup.c index 4a16a37229..d729263708 100644 --- a/block/backup.c +++ b/block/backup.c @@ -545,15 +545,15 @@ static const BlockJobDriver backup_job_driver =3D { .drain =3D backup_drain, }; =20 -BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - BlockDriverState *target, int64_t speed, - MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, - bool compress, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, - int creation_flags, - BlockCompletionFunc *cb, void *opaque, - BlockJobTxn *txn, Error **errp) +BlockJob *backup_job_create(const char *job_id, bool manual, + BlockDriverState *bs, BlockDriverState *target, + int64_t speed, MirrorSyncMode sync_mode, + BdrvDirtyBitmap *sync_bitmap, bool compress, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, + int creation_flags, + BlockCompletionFunc *cb, void *opaque, + BlockJobTxn *txn, Error **errp) { int64_t len; BlockDriverInfo bdi; @@ -621,7 +621,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDr= iverState *bs, } =20 /* job->common.len is fixed, so we can't allow resize */ - job =3D block_job_create(job_id, &backup_job_driver, bs, + job =3D block_job_create(job_id, &backup_job_driver, manual, bs, BLK_PERM_CONSISTENT_READ, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD, diff --git a/block/commit.c b/block/commit.c index bb6c904704..920fdabcc2 100644 --- a/block/commit.c +++ b/block/commit.c @@ -289,7 +289,7 @@ void commit_start(const char *job_id, BlockDriverState = *bs, return; } =20 - s =3D block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL, + s =3D block_job_create(job_id, &commit_job_driver, false, bs, 0, BLK_P= ERM_ALL, speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp); if (!s) { return; diff --git a/block/mirror.c b/block/mirror.c index c9badc1203..8e8d3589f2 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1166,7 +1166,7 @@ static void mirror_start_job(const char *job_id, Bloc= kDriverState *bs, } =20 /* Make sure that the source is not resized while the job is running */ - s =3D block_job_create(job_id, driver, mirror_top_bs, + s =3D block_job_create(job_id, driver, false, mirror_top_bs, BLK_PERM_CONSISTENT_READ, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANG= ED | BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed, diff --git a/block/replication.c b/block/replication.c index b1ea3caa4b..3ab0a08cd7 100644 --- a/block/replication.c +++ b/block/replication.c @@ -563,8 +563,9 @@ static void replication_start(ReplicationState *rs, Rep= licationMode mode, bdrv_op_block_all(top_bs, s->blocker); bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker); =20 - job =3D backup_job_create(NULL, s->secondary_disk->bs, s->hidden_d= isk->bs, - 0, MIRROR_SYNC_MODE_NONE, NULL, false, + job =3D backup_job_create(NULL, false, s->secondary_disk->bs, + s->hidden_disk->bs, 0, MIRROR_SYNC_MODE_NO= NE, + NULL, false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERN= AL, backup_job_completed, bs, NULL, &local_err= ); diff --git a/block/stream.c b/block/stream.c index 499cdacdb0..f31785965c 100644 --- a/block/stream.c +++ b/block/stream.c @@ -244,7 +244,7 @@ void stream_start(const char *job_id, BlockDriverState = *bs, /* Prevent concurrent jobs trying to modify the graph structure here, = we * already have our own plans. Also don't allow resize as the image si= ze is * queried only at the job start and then cached. */ - s =3D block_job_create(job_id, &stream_job_driver, bs, + s =3D block_job_create(job_id, &stream_job_driver, false, bs, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANG= ED | BLK_PERM_GRAPH_MOD, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANG= ED | diff --git a/blockdev.c b/blockdev.c index 8e977eef11..2c0773bba7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3373,7 +3373,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup,= BlockJobTxn *txn, } } =20 - job =3D backup_job_create(backup->job_id, bs, target_bs, backup->speed, + job =3D backup_job_create(backup->job_id, false, bs, target_bs, backup= ->speed, backup->sync, bmap, backup->compress, backup->on_source_error, backup->on_target_err= or, BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err= ); @@ -3452,7 +3452,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, = BlockJobTxn *txn, goto out; } } - job =3D backup_job_create(backup->job_id, bs, target_bs, backup->speed, + job =3D backup_job_create(backup->job_id, false, bs, target_bs, backup= ->speed, backup->sync, NULL, backup->compress, backup->on_source_error, backup->on_target_err= or, BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err= ); diff --git a/blockjob.c b/blockjob.c index f5cea84e73..9850d70cb0 100644 --- a/blockjob.c +++ b/blockjob.c @@ -648,7 +648,7 @@ static void block_job_event_completed(BlockJob *job, co= nst char *msg) */ =20 void *block_job_create(const char *job_id, const BlockJobDriver *driver, - BlockDriverState *bs, uint64_t perm, + bool manual, BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, int64_t speed, int flags, BlockCompletionFunc *cb, void *opaque, Error **errp) { @@ -703,6 +703,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, job->paused =3D true; job->pause_count =3D 1; job->refcnt =3D 1; + job->manual =3D manual; aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, QEMU_CLOCK_REALTIME, SCALE_NS, block_job_sleep_timer_cb, job); diff --git a/include/block/block_int.h b/include/block/block_int.h index 29cafa4236..08f5046c63 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -981,9 +981,9 @@ void mirror_start(const char *job_id, BlockDriverState = *bs, * Create a backup operation on @bs. Clusters in @bs are written to @targ= et * until the job is cancelled or manually completed. */ -BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - BlockDriverState *target, int64_t speed, - MirrorSyncMode sync_mode, +BlockJob *backup_job_create(const char *job_id, bool manual, + BlockDriverState *bs, BlockDriverState *target, + int64_t speed, MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, bool compress, BlockdevOnError on_source_error, diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 00403d9482..b94d0c9fa6 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -141,6 +141,11 @@ typedef struct BlockJob { */ QEMUTimer sleep_timer; =20 + /* Set to true when management API has requested 2.12+ job lifetime + * management semantics. + */ + bool manual; + /** Non-NULL if this job is part of a transaction */ BlockJobTxn *txn; QLIST_ENTRY(BlockJob) txn_list; diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index c9b23b0cc9..a24c3f90e5 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -132,7 +132,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, - BlockDriverState *bs, uint64_t perm, + bool manual, BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, int64_t speed, int flags, BlockCompletionFunc *cb, void *opaque, Error **errp= ); =20 diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index d760e2b243..184c5663b8 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -541,8 +541,8 @@ static void test_blockjob_common(enum drain_type drain_= type) blk_target =3D blk_new(BLK_PERM_ALL, BLK_PERM_ALL); blk_insert_bs(blk_target, target, &error_abort); =20 - job =3D block_job_create("job0", &test_job_driver, src, 0, BLK_PERM_AL= L, 0, - 0, NULL, NULL, &error_abort); + job =3D block_job_create("job0", &test_job_driver, false, src, 0, + BLK_PERM_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); =20 diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 3591c9617f..2efaa554c0 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -101,7 +101,7 @@ static BlockJob *test_block_job_start(unsigned int iter= ations, g_assert_nonnull(bs); =20 snprintf(job_id, sizeof(job_id), "job%u", counter++); - s =3D block_job_create(job_id, &test_block_job_driver, bs, + s =3D block_job_create(job_id, &test_block_job_driver, false, bs, 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, test_block_job_cb, data, &error_abort); s->iterations =3D iterations; diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 23bdf1a932..f08da8dca9 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -30,8 +30,8 @@ static BlockJob *do_test_id(BlockBackend *blk, const char= *id, BlockJob *job; Error *errp =3D NULL; =20 - job =3D block_job_create(id, &test_block_job_driver, blk_bs(blk), - 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, block_jo= b_cb, + job =3D block_job_create(id, &test_block_job_driver, false, blk_bs(blk= ), 0, + BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, block_job_c= b, NULL, &errp); if (should_succeed) { g_assert_null(errp); --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019058371221.78644240700226; Fri, 26 Jan 2018 18:10:58 -0800 (PST) Received: from localhost ([::1]:43679 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFxH-0007Ie-Ae for importer@patchew.org; Fri, 26 Jan 2018 21:10:55 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37175) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs1-0000k5-Vt for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs0-0008LI-FS for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:29 -0500 Received: from mx1.redhat.com ([209.132.183.28]:48058) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFrx-0008IJ-4V; Fri, 26 Jan 2018 21:05:25 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5670B1555A; Sat, 27 Jan 2018 02:05:24 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9BB0F5457C; Sat, 27 Jan 2018 02:05:23 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:03 -0500 Message-Id: <20180127020515.27137-3-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Sat, 27 Jan 2018 02:05:24 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 02/14] blockjobs: Add status enum 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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're about to add several new states, and booleans are becoming unwieldly and difficult to reason about. To this end, add a new "status" field and add our existing states in a redundant manner alongside the bools they are replacing: UNDEFINED: Placeholder, default state. CREATED: replaces (paused && !busy) RUNNING: replaces effectively (!paused && busy) PAUSED: Nearly redundant with info->paused, which shows pause_count. This reports the actual status of the job, which almost always matches the paused request status. It differs in that it is strictly only true when the job has actually gone dormant. READY: replaces job->ready. New state additions in coming commits will not be quite so redundant: WAITING: Waiting on Transaction. This job has finished all the work it can until the transaction converges, fails, or is canceled. This status does not feature for non-transactional jobs. PENDING: Pending authorization from user. This job has finished all the work it can until the job or transaction is finalized via block_job_finalize. If this job is in a transaction, it has already left the WAITING status. CONCLUDED: Job has ceased all operations and has a return code available for query and may be dismissed via block_job_dismiss. Signed-off-by: John Snow --- blockjob.c | 10 ++++++++++ include/block/blockjob.h | 4 ++++ qapi/block-core.json | 17 ++++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/blockjob.c b/blockjob.c index 9850d70cb0..6eb783a354 100644 --- a/blockjob.c +++ b/blockjob.c @@ -321,6 +321,7 @@ void block_job_start(BlockJob *job) job->pause_count--; job->busy =3D true; job->paused =3D false; + job->status =3D BLOCK_JOB_STATUS_RUNNING; bdrv_coroutine_enter(blk_bs(job->blk), job->co); } =20 @@ -601,6 +602,10 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **e= rrp) info->speed =3D job->speed; info->io_status =3D job->iostatus; info->ready =3D job->ready; + if (job->manual) { + info->has_status =3D true; + info->status =3D job->status; + } return info; } =20 @@ -704,6 +709,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, job->pause_count =3D 1; job->refcnt =3D 1; job->manual =3D manual; + job->status =3D 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); @@ -808,9 +814,12 @@ void coroutine_fn block_job_pause_point(BlockJob *job) } =20 if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { + BlockJobStatus status =3D job->status; + job->status =3D BLOCK_JOB_STATUS_PAUSED; job->paused =3D true; block_job_do_yield(job, -1); job->paused =3D false; + job->status =3D status; } =20 if (job->driver->resume) { @@ -916,6 +925,7 @@ void block_job_iostatus_reset(BlockJob *job) =20 void block_job_event_ready(BlockJob *job) { + job->status =3D BLOCK_JOB_STATUS_READY; job->ready =3D true; =20 if (block_job_is_internal(job)) { diff --git a/include/block/blockjob.h b/include/block/blockjob.h index b94d0c9fa6..d8e7df7e6e 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -146,6 +146,10 @@ typedef struct BlockJob { */ bool manual; =20 + /* Current state, using 2.12+ state names + */ + BlockJobStatus status; + /** Non-NULL if this job is part of a transaction */ BlockJobTxn *txn; QLIST_ENTRY(BlockJob) txn_list; diff --git a/qapi/block-core.json b/qapi/block-core.json index 8225308904..eac89754c1 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -955,6 +955,18 @@ { 'enum': 'BlockJobType', 'data': ['commit', 'stream', 'mirror', 'backup'] } =20 +## +# @BlockJobStatus: +# +# Block Job State +# +# +# +# Since: 2.12 +## +{ 'enum': 'BlockJobStatus', + 'data': ['undefined', 'created', 'running', 'paused', 'ready'] } + ## # @BlockJobInfo: # @@ -981,12 +993,15 @@ # # @ready: true if the job may be completed (since 2.2) # +# @status: Current job state/status (since 2.12) +# # Since: 1.1 ## { 'struct': 'BlockJobInfo', 'data': {'type': 'str', 'device': 'str', 'len': 'int', 'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'in= t', - 'io-status': 'BlockDeviceIoStatus', 'ready': 'bool'} } + 'io-status': 'BlockDeviceIoStatus', 'ready': 'bool', + '*status': 'BlockJobStatus' } } =20 ## # @query-block-jobs: --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517018871825856.2927654658665; Fri, 26 Jan 2018 18:07:51 -0800 (PST) Received: from localhost ([::1]:43656 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFu9-0003MR-Sl for importer@patchew.org; Fri, 26 Jan 2018 21:07:41 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37170) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs1-0000jP-TP for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs0-0008Li-Ma for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:29 -0500 Received: from mx1.redhat.com ([209.132.183.28]:48060) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFrx-0008Il-TJ; Fri, 26 Jan 2018 21:05:26 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2FC3315561; Sat, 27 Jan 2018 02:05:25 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 750745457C; Sat, 27 Jan 2018 02:05:24 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:04 -0500 Message-Id: <20180127020515.27137-4-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Sat, 27 Jan 2018 02:05:25 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 03/14] blockjobs: add state transition table 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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 state transition table has mostly been implied. We're about to make it a bit more complex, so let's make the STM explicit instead. Perform state transitions with a function that for now just asserts the transition is appropriate. undefined: May only transition to 'created'. created: May only transition to 'running'. It cannot transition to pause directly, but if a created job is requested to pause prior to starting, it will transition synchronously to 'running' and then to 'paused'. running: May transition either to 'paused' or 'ready'. paused: May transition to either 'running' or 'ready', but only in terms of returning to that prior state. p->r->y is not possible, but this is not encapsulated by the STM table. ready: May transition to paused. Signed-off-by: John Snow --- blockjob.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/blockjob.c b/blockjob.c index 6eb783a354..d084a1e318 100644 --- a/blockjob.c +++ b/blockjob.c @@ -42,6 +42,35 @@ * 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 */ + /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0}, + /* C: */ [BLOCK_JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0}, + /* R: */ [BLOCK_JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1}, + /* P: */ [BLOCK_JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 1}, + /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 1, 0}, +}; + +static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) +{ + BlockJobStatus s0 =3D job->status; + if (s0 =3D=3D s1) { + return; + } + assert(s1 >=3D 0 && s1 <=3D BLOCK_JOB_STATUS__MAX); + assert(BlockJobSTT[s0][s1]); + switch (s1) { + case BLOCK_JOB_STATUS_WAITING: + case BLOCK_JOB_STATUS_PENDING: + case BLOCK_JOB_STATUS_CONCLUDED: + assert(job->manual); + default: + break; + } + job->status =3D s1; +} + static void block_job_lock(void) { qemu_mutex_lock(&block_job_mutex); @@ -321,7 +350,7 @@ void block_job_start(BlockJob *job) job->pause_count--; job->busy =3D true; job->paused =3D false; - job->status =3D BLOCK_JOB_STATUS_RUNNING; + block_job_state_transition(job, BLOCK_JOB_STATUS_RUNNING); bdrv_coroutine_enter(blk_bs(job->blk), job->co); } =20 @@ -709,7 +738,7 @@ void *block_job_create(const char *job_id, const BlockJ= obDriver *driver, job->pause_count =3D 1; job->refcnt =3D 1; job->manual =3D manual; - job->status =3D BLOCK_JOB_STATUS_CREATED; + 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); @@ -815,11 +844,11 @@ void coroutine_fn block_job_pause_point(BlockJob *job) =20 if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { BlockJobStatus status =3D job->status; - job->status =3D BLOCK_JOB_STATUS_PAUSED; + block_job_state_transition(job, BLOCK_JOB_STATUS_PAUSED); job->paused =3D true; block_job_do_yield(job, -1); job->paused =3D false; - job->status =3D status; + block_job_state_transition(job, status); } =20 if (job->driver->resume) { @@ -925,7 +954,7 @@ void block_job_iostatus_reset(BlockJob *job) =20 void block_job_event_ready(BlockJob *job) { - job->status =3D BLOCK_JOB_STATUS_READY; + block_job_state_transition(job, BLOCK_JOB_STATUS_READY); job->ready =3D true; =20 if (block_job_is_internal(job)) { --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517018901014986.0370702905391; Fri, 26 Jan 2018 18:08:21 -0800 (PST) Received: from localhost ([::1]:43658 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFuk-0004El-9p for importer@patchew.org; Fri, 26 Jan 2018 21:08:18 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37218) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs3-0000oz-2E for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:32 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs1-0008Mj-Oh for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:30 -0500 Received: from mx1.redhat.com ([209.132.183.28]:48064) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFry-0008JQ-Op; Fri, 26 Jan 2018 21:05:26 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0EA4E1555A; Sat, 27 Jan 2018 02:05:26 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5183A5457C; Sat, 27 Jan 2018 02:05:25 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:05 -0500 Message-Id: <20180127020515.27137-5-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Sat, 27 Jan 2018 02:05:26 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 04/14] blockjobs: RFC add block_job_verb permission table 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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" Which commands are appropriate for jobs in which state is also somewhat burdensome to keep track of. Introduce a verbs table that, as of this RFC patch, does nothing but serve as a declaration of intent. (At the very least, it forced me to consider all of the possibilities.) If this idea seems appealing, I can expand the verbs concept into a list of interfaces to consult the table and refuse inappropriate commands, mostly serving as new errors for the QMP interface. cancel: can apply to any created, running, paused or ready job. pause: can apply to any created, running, or ready job. Addition pauses can and do stack, so a paused job can also be paused. Note that a pause from the QMP context is treated separately and does not stack. resume: Only a paused job can be resumed. Only a job that has been paused via QMP can be resumed via QMP. set-speed: Any created, running, paused or ready job can tolerate a set-speed request. complete: Only a ready job may accept a complete request. Signed-off-by: John Snow --- blockjob.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/blockjob.c b/blockjob.c index d084a1e318..ea216aca5e 100644 --- a/blockjob.c +++ b/blockjob.c @@ -52,6 +52,24 @@ bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS= __MAX] =3D { /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 1, 0}, }; =20 +enum BlockJobVerb { + BLOCK_JOB_VERB_CANCEL, + BLOCK_JOB_VERB_PAUSE, + BLOCK_JOB_VERB_RESUME, + BLOCK_JOB_VERB_SET_SPEED, + BLOCK_JOB_VERB_COMPLETE, + BLOCK_JOB_VERB__MAX +}; + +bool BlockJobVerb[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] =3D { + /* U, C, R, P, Y */ + [BLOCK_JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1}, + [BLOCK_JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1}, + [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0}, + [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1}, + [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1}, +}; + static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) { BlockJobStatus s0 =3D job->status; --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019135927643.3768217663294; Fri, 26 Jan 2018 18:12:15 -0800 (PST) Received: from localhost ([::1]:43682 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFyX-0008WJ-13 for importer@patchew.org; Fri, 26 Jan 2018 21:12:13 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37266) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs4-0000t7-IY for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:35 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs2-0008Nv-L0 for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:32 -0500 Received: from mx1.redhat.com ([209.132.183.28]:44690) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFrz-0008Jv-JX; Fri, 26 Jan 2018 21:05:27 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D717B81E03; Sat, 27 Jan 2018 02:05:26 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2D08D5457C; Sat, 27 Jan 2018 02:05:26 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:06 -0500 Message-Id: <20180127020515.27137-6-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Sat, 27 Jan 2018 02:05:26 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 05/14] blockjobs: add block_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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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" For jobs that have reached their terminal state, prior to having their last reference put down (meaning jobs that have completed successfully, unsuccessfully, or have been canceled), allow the user to dismiss the job's lingering status report via block-job-dismiss. This gives management APIs the chance to conclusively determine if a job failed or succeeded, even if the event broadcast was missed. Note that jobs do not yet linger in any such state, they are freed immediately upon reaching this previously-unnamed state. such a state is added immediately in the next commit. Valid objects: Concluded: (added in a future commit); dismisses the concluded job. Signed-off-by: John Snow --- block/trace-events | 1 + blockdev.c | 14 ++++++++++++++ blockjob.c | 30 ++++++++++++++++++++++++++++++ include/block/blockjob.h | 9 +++++++++ qapi/block-core.json | 19 +++++++++++++++++++ 5 files changed, 73 insertions(+) diff --git a/block/trace-events b/block/trace-events index 11c8d5f590..8f61566770 100644 --- a/block/trace-events +++ b/block/trace-events @@ -46,6 +46,7 @@ qmp_block_job_cancel(void *job) "job %p" qmp_block_job_pause(void *job) "job %p" qmp_block_job_resume(void *job) "job %p" qmp_block_job_complete(void *job) "job %p" +qmp_block_job_dismiss(void *job) "job %p" qmp_block_stream(void *bs, void *job) "bs %p job %p" =20 # block/file-win32.c diff --git a/blockdev.c b/blockdev.c index 2c0773bba7..5e8edff322 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3849,6 +3849,20 @@ void qmp_block_job_complete(const char *device, Erro= r **errp) aio_context_release(aio_context); } =20 +void qmp_block_job_dismiss(const char *id, Error **errp) +{ + AioContext *aio_context; + BlockJob *job =3D find_block_job(id, &aio_context, errp); + + if (!job) { + return; + } + + trace_qmp_block_job_dismiss(job); + block_job_dismiss(&job, errp); + aio_context_release(aio_context); +} + void qmp_change_backing_file(const char *device, const char *image_node_name, const char *backing_file, diff --git a/blockjob.c b/blockjob.c index ea216aca5e..5531f5c2ab 100644 --- a/blockjob.c +++ b/blockjob.c @@ -58,6 +58,7 @@ enum BlockJobVerb { BLOCK_JOB_VERB_RESUME, BLOCK_JOB_VERB_SET_SPEED, BLOCK_JOB_VERB_COMPLETE, + BLOCK_JOB_VERB_DISMISS, BLOCK_JOB_VERB__MAX }; =20 @@ -68,6 +69,7 @@ bool BlockJobVerb[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__= MAX] =3D { [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0}, [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1}, [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1}, + [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0}, }; =20 static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) @@ -426,6 +428,13 @@ static void block_job_cancel_async(BlockJob *job) job->cancelled =3D true; } =20 +static void block_job_do_dismiss(BlockJob *job) +{ + assert(job && job->manual =3D=3D true); + block_job_state_transition(job, BLOCK_JOB_STATUS_UNDEFINED); + block_job_unref(job); +} + static int block_job_finish_sync(BlockJob *job, void (*finish)(BlockJob *, Error **errp), Error **errp) @@ -455,6 +464,9 @@ 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; + if (job->manual) { + block_job_do_dismiss(job); + } block_job_unref(job); return ret; } @@ -570,6 +582,24 @@ void block_job_complete(BlockJob *job, Error **errp) job->driver->complete(job, errp); } =20 +void block_job_dismiss(BlockJob **jobptr, Error **errp) +{ + BlockJob *job =3D *jobptr; + /* similarly to _complete, this is QMP-interface only. */ + assert(job->id); + if (!job->manual) { + error_setg(errp, "The active block job '%s' was not started with " + "\'manual\': true, and so cannot be dismissed as it wil= l " + "clean up after itself automatically", job->id); + return; + } + + error_setg(errp, "unimplemented"); + + block_job_do_dismiss(job); + *jobptr =3D NULL; +} + void block_job_user_pause(BlockJob *job) { job->user_paused =3D true; diff --git a/include/block/blockjob.h b/include/block/blockjob.h index d8e7df7e6e..7c71dc0ca7 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -241,6 +241,15 @@ void block_job_cancel(BlockJob *job); */ void block_job_complete(BlockJob *job, 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_query: * @job: The job to get information about. diff --git a/qapi/block-core.json b/qapi/block-core.json index eac89754c1..32aefa5a27 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2198,6 +2198,25 @@ ## { 'command': 'block-job-complete', 'data': { 'device': 'str' } } =20 +## +# @block-job-dismiss: +# +# For jobs that have already concluded, remove them from the block-job-que= ry +# list. This command only needs to be run for jobs which were started with +# QEMU 2.12+ job lifetime management semantics. +# +# This command will refuse to operate on any job that has not yet reached +# its terminal state. "cancel" or "complete" will still need to be used as +# appropriate. +# +# @id: The job identifier. +# +# Returns: Nothing on success +# +# Since: 2.12 +## +{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' } } + ## # @BlockdevDiscardOptions: # --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) 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=temperror (zoho.com: Error in retrieving data from DNS) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019099694396.224370687783; Fri, 26 Jan 2018 18:11:39 -0800 (PST) Received: from localhost ([::1]:43681 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFxy-00084P-Q7 for importer@patchew.org; Fri, 26 Jan 2018 21:11:38 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37273) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs4-0000tx-Ty for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:35 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs3-0008P2-Tm for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:32 -0500 Received: from mx1.redhat.com ([209.132.183.28]:43028) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs0-0008Ku-EB; Fri, 26 Jan 2018 21:05:28 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B520C1602DD; Sat, 27 Jan 2018 02:05:27 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0636B608F7; Sat, 27 Jan 2018 02:05:26 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:07 -0500 Message-Id: <20180127020515.27137-7-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Sat, 27 Jan 2018 02:05:27 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 06/14] blockjobs: add CONCLUDED state 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_6 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" add a new state "CONCLUDED" that identifies a job that has ceased all operations. The wording was chosen to avoid any phrasing that might imply success, error, or cancellation. The task has simply ceased all operation and can never again perform any work. ("finished", "done", and "completed" might all imply success.) Valid transitions: Running -> Concluded (cancellation, normal completion) Paused -> Concluded (cancellation) Ready -> Concluded (cancellation, manual completion) Concluded -> Undefined (immediately prior to destruction) Valid verbs: Dismiss: culls the job and job info from the query list. Signed-off-by: John Snow --- blockjob.c | 56 +++++++++++++++++++++++++++++++++++++-----------= ---- qapi/block-core.json | 8 +++++--- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/blockjob.c b/blockjob.c index 5531f5c2ab..0083fd7b0c 100644 --- a/blockjob.c +++ b/blockjob.c @@ -44,12 +44,13 @@ 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 */ - /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0}, - /* C: */ [BLOCK_JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0}, - /* R: */ [BLOCK_JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1}, - /* P: */ [BLOCK_JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 1}, - /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 1, 0}, + /* U, C, R, P, Y, E */ + /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0, 0}, + /* C: */ [BLOCK_JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0, 0}, + /* R: */ [BLOCK_JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1, 1}, + /* P: */ [BLOCK_JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 1, 1}, + /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 1, 0, 1}, + /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] =3D {1, 0, 0, 0, 0, 0}, }; =20 enum BlockJobVerb { @@ -63,13 +64,13 @@ enum BlockJobVerb { }; =20 bool BlockJobVerb[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] =3D { - /* U, C, R, P, Y */ - [BLOCK_JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1}, - [BLOCK_JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1}, - [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0}, - [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1}, - [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1}, - [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0}, + /* U, C, R, P, Y, E */ + [BLOCK_JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1, 0}, + [BLOCK_JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1, 0}, + [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0, 0}, + [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1, 0}, + [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1, 0}, + [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 1}, }; =20 static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) @@ -108,6 +109,7 @@ static void __attribute__((__constructor__)) block_job_= init(void) =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_concluded(BlockJob *job); static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)); =20 /* Transactional group of block jobs */ @@ -412,6 +414,8 @@ static void block_job_completed_single(BlockJob *job) QLIST_REMOVE(job, txn_list); block_job_txn_unref(job->txn); } + + block_job_event_concluded(job); block_job_unref(job); } =20 @@ -592,10 +596,14 @@ void block_job_dismiss(BlockJob **jobptr, Error **err= p) "\'manual\': true, and so cannot be dismissed as it wil= l " "clean up after itself automatically", job->id); return; + } else if (job->status !=3D BLOCK_JOB_STATUS_CONCLUDED) { + error_setg(errp, "The active block job '%s', status: '%s', has not= yet " + "concluded, and cannot be dismissed yet", + job->id, + qapi_enum_lookup(&BlockJobStatus_lookup, job->status)); + return; } =20 - error_setg(errp, "unimplemented"); - block_job_do_dismiss(job); *jobptr =3D NULL; } @@ -622,7 +630,9 @@ void block_job_user_resume(BlockJob *job) =20 void block_job_cancel(BlockJob *job) { - if (block_job_started(job)) { + if (job->status =3D=3D BLOCK_JOB_STATUS_CONCLUDED) { + return; + } else if (block_job_started(job)) { block_job_cancel_async(job); block_job_enter(job); } else { @@ -724,6 +734,14 @@ static void block_job_event_completed(BlockJob *job, c= onst char *msg) &error_abort); } =20 +static void block_job_event_concluded(BlockJob *job) +{ + if (block_job_is_internal(job) || !job->manual) { + return; + } + block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED); +} + /* * API for block job drivers and the block layer. These functions are * declared in blockjob_int.h. @@ -814,6 +832,12 @@ void *block_job_create(const char *job_id, const Block= JobDriver *driver, return NULL; } } + + /* Hang on to an extra reference on behalf of the QMP monitor */ + if (job->manual) { + block_job_ref(job); + } + return job; } =20 diff --git a/qapi/block-core.json b/qapi/block-core.json index 32aefa5a27..f27c7054d2 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -965,7 +965,8 @@ # Since: 2.12 ## { 'enum': 'BlockJobStatus', - 'data': ['undefined', 'created', 'running', 'paused', 'ready'] } + 'data': ['undefined', 'created', 'running', 'paused', 'ready', + 'concluded' ] } =20 ## # @BlockJobInfo: @@ -2206,8 +2207,9 @@ # QEMU 2.12+ job lifetime management semantics. # # This command will refuse to operate on any job that has not yet reached -# its terminal state. "cancel" or "complete" will still need to be used as -# appropriate. +# its terminal state, BLOCK_JOB_STATUS_CONCLUDED. For jobs that make use of +# BLOCK_JOB_READY event, block-job-cancel or block-job-complete will still= need +# to be used as appropriate. # # @id: The job identifier. # --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019276547527.3667153645723; Fri, 26 Jan 2018 18:14:36 -0800 (PST) Received: from localhost ([::1]:43806 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efG0m-0002Bw-4v for importer@patchew.org; Fri, 26 Jan 2018 21:14:32 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37329) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs7-00010Q-D2 for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:36 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs4-0008Pp-J6 for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:35 -0500 Received: from mx1.redhat.com ([209.132.183.28]:35248) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs1-0008M0-CQ; Fri, 26 Jan 2018 21:05:29 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A9B02EC0AA; Sat, 27 Jan 2018 02:05:28 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id D84FF5457C; Sat, 27 Jan 2018 02:05:27 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:08 -0500 Message-Id: <20180127020515.27137-8-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Sat, 27 Jan 2018 02:05:28 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 07/14] blockjobs: ensure abort is called for cancelled 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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" Presently, even if a job is canceled post-completion as a result of a failing peer in a transaction, it will still call .commit because nothing has updated or changed its return code. The reason why this does not cause problems currently is because backup's implementation of .commit checks for cancellation itself. I'd like to simplify this contract: (1) Abort is called if the job/transaction fails (2) Commit is called if the job/transaction succeeds To this end: A job's return code, if 0, will be forcibly set as -ECANCELED if that job has already concluded. Remove the now redundant check in the backup job implementation. This does NOT affect mirror jobs that are "canceled" during their synchronous phase. The mirror job itself forcibly sets the canceled property to false prior to ceding control, so such cases will invoke the "commit" callback. Signed-off-by: John Snow --- block/backup.c | 2 +- blockjob.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/block/backup.c b/block/backup.c index d729263708..a17248feab 100644 --- a/block/backup.c +++ b/block/backup.c @@ -206,7 +206,7 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *= job, int ret) BdrvDirtyBitmap *bm; BlockDriverState *bs =3D blk_bs(job->common.blk); =20 - if (ret < 0 || block_job_is_cancelled(&job->common)) { + if (ret < 0) { /* Merge the successor back into the parent, delete nothing. */ bm =3D bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL); assert(bm); diff --git a/blockjob.c b/blockjob.c index 0083fd7b0c..3d678d6ce2 100644 --- a/blockjob.c +++ b/blockjob.c @@ -380,6 +380,11 @@ static void block_job_completed_single(BlockJob *job) { assert(job->completed); =20 + /* Ensure abort is called and QMP client is notified of cancellation */ + if (job->ret =3D=3D 0 && block_job_is_cancelled(job)) { + job->ret =3D -ECANCELED; + } + if (!job->ret) { if (job->driver->commit) { job->driver->commit(job); --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15170193093791022.0342997615969; Fri, 26 Jan 2018 18:15:09 -0800 (PST) Received: from localhost ([::1]:43813 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efG1M-0002kS-J8 for importer@patchew.org; Fri, 26 Jan 2018 21:15:08 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37363) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs8-00014F-Mx for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:37 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs7-0008Se-G7 for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:36 -0500 Received: from mx1.redhat.com ([209.132.183.28]:42314) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs2-0008Mc-8J; Fri, 26 Jan 2018 21:05:30 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 848B2F1948; Sat, 27 Jan 2018 02:05:29 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id CCF955457C; Sat, 27 Jan 2018 02:05:28 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:09 -0500 Message-Id: <20180127020515.27137-9-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Sat, 27 Jan 2018 02:05:29 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 08/14] blockjobs: add commit, abort, clean helpers 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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 completed_single function is getting a little mucked up with checking to see which callbacks exist, so let's factor them out. Signed-off-by: John Snow --- blockjob.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/blockjob.c b/blockjob.c index 3d678d6ce2..1b169a0814 100644 --- a/blockjob.c +++ b/blockjob.c @@ -376,6 +376,29 @@ void block_job_start(BlockJob *job) bdrv_coroutine_enter(blk_bs(job->blk), job->co); } =20 +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); + } +} + static void block_job_completed_single(BlockJob *job) { assert(job->completed); @@ -386,17 +409,11 @@ static void block_job_completed_single(BlockJob *job) } =20 if (!job->ret) { - if (job->driver->commit) { - job->driver->commit(job); - } + block_job_commit(job); } else { - if (job->driver->abort) { - job->driver->abort(job); - } - } - if (job->driver->clean) { - job->driver->clean(job); + block_job_abort(job); } + block_job_clean(job); =20 if (job->cb) { job->cb(job->opaque, job->ret); --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019272417881.0656761970969; Fri, 26 Jan 2018 18:14:32 -0800 (PST) Received: from localhost ([::1]:43804 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efG0c-00024Q-DC for importer@patchew.org; Fri, 26 Jan 2018 21:14:22 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37365) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFs8-00014G-O1 for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:37 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs7-0008SS-EM for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:36 -0500 Received: from mx1.redhat.com ([209.132.183.28]:42320) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs3-0008Nr-3F; Fri, 26 Jan 2018 21:05:31 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 60397F195A; Sat, 27 Jan 2018 02:05:30 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id A6DF7608F7; Sat, 27 Jan 2018 02:05:29 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:10 -0500 Message-Id: <20180127020515.27137-10-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Sat, 27 Jan 2018 02:05:30 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 09/14] blockjobs: add prepare callback 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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" Some jobs, upon finalization, may need to perform some work that can still fail. If these jobs are part of a transaction, it's important that these callbacks fail the entire transaction. Thus, we allow for a new callback in addition to commit/abort/clean that allows us the opportunity to have fairly late-breaking failures in the transactional process. The expected flow is as such: - All jobs in a transaction converge to the WAITING state (added in a forthcoming commit) - All jobs prepare to call either commit/abort - If any job fails, is canceled, or fails preparation, all jobs call their .abort callback. - All jobs enter the PENDING state, awaiting manual intervention (also added in a forthcoming commit) - block-job-finalize is issued by the user/management layer - All jobs call their commit callbacks. Signed-off-by: John Snow --- blockjob.c | 35 ++++++++++++++++++++++++++++++++++- include/block/blockjob.h | 3 +++ include/block/blockjob_int.h | 10 ++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/blockjob.c b/blockjob.c index 1b169a0814..e52b4c4ce0 100644 --- a/blockjob.c +++ b/blockjob.c @@ -376,9 +376,21 @@ void block_job_start(BlockJob *job) bdrv_coroutine_enter(blk_bs(job->blk), job->co); } =20 +static int block_job_prepare(BlockJob *job) +{ + if (job->prepared) { + return job->ret; + } + job->prepared =3D true; + 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); + assert(!job->ret && job->prepared); if (job->driver->commit) { job->driver->commit(job); } @@ -408,6 +420,9 @@ static void block_job_completed_single(BlockJob *job) job->ret =3D -ECANCELED; } =20 + /* NB: updates job->ret, only if not called on this job yet */ + block_job_prepare(job); + if (!job->ret) { block_job_commit(job); } else { @@ -545,6 +560,8 @@ static void block_job_completed_txn_success(BlockJob *j= ob) AioContext *ctx; BlockJobTxn *txn =3D job->txn; BlockJob *other_job, *next; + int rc =3D 0; + /* * Successful completion, see if there are other running jobs in this * txn. @@ -554,6 +571,22 @@ static void block_job_completed_txn_success(BlockJob *= job) return; } } + + /* Jobs may require some prep-work to complete without failure */ + QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { + ctx =3D blk_get_aio_context(other_job->blk); + aio_context_acquire(ctx); + assert(other_job->ret =3D=3D 0); + rc =3D block_job_prepare(job); + aio_context_release(ctx); + + /* This job failed. Cancel this transaction */ + if (rc) { + block_job_completed_txn_abort(other_job); + return; + } + } + /* We are the last completed job, commit the transaction. */ QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { ctx =3D blk_get_aio_context(other_job->blk); diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 7c71dc0ca7..5f73fc8831 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -150,6 +150,9 @@ typedef struct BlockJob { */ BlockJobStatus status; =20 + /* Job has made preparations to call either commit or abort */ + bool prepared; + /** Non-NULL if this job is part of a transaction */ BlockJobTxn *txn; QLIST_ENTRY(BlockJob) txn_list; diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index a24c3f90e5..689d1bc659 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -53,6 +53,16 @@ struct BlockJobDriver { */ void (*complete)(BlockJob *job, Error **errp); =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 when all the jobs * belonging to the same transaction complete; or upon this job's --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019434714967.938920704753; Fri, 26 Jan 2018 18:17:14 -0800 (PST) Received: from localhost ([::1]:43850 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efG3L-0004Uw-PW for importer@patchew.org; Fri, 26 Jan 2018 21:17:11 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37415) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFsA-00019t-DU for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs9-0008U8-0z for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:38 -0500 Received: from mx1.redhat.com ([209.132.183.28]:35282) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs4-0008Op-3A; Fri, 26 Jan 2018 21:05:32 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5F1798EB0F; Sat, 27 Jan 2018 02:05:31 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8268A5457C; Sat, 27 Jan 2018 02:05:30 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:11 -0500 Message-Id: <20180127020515.27137-11-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Sat, 27 Jan 2018 02:05:31 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 10/14] blockjobs: Add waiting 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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" For jobs that are stuck waiting on others in a transaction, it would be nice to know that they are no longer "running" in that sense, but instead are waiting on other jobs in the transaction. Jobs that are "waiting" in this sense cannot be meaningfully altered any longer as they have left their running loop. The only meaningful user verb for jobs in this state is "cancel," which will cancel the whole transaction, too. Valid transitions: Running -> Waiting (transactional, non-mirror jobs upon completion) Ready -> Waiting (hypothetically: transactional mirror jobs upon block-job-complete) Waiting -> Concluded (transactional jobs of any kind upon convergence) Valid verbs: Cancel: A waiting job may still be canceled. Signed-off-by: John Snow --- blockjob.c | 45 +++++++++++++++++++++++++++++++-------------- qapi/block-core.json | 25 ++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/blockjob.c b/blockjob.c index e52b4c4ce0..6a3a630517 100644 --- a/blockjob.c +++ b/blockjob.c @@ -44,13 +44,14 @@ 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, E */ - /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0, 0}, - /* C: */ [BLOCK_JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0, 0}, - /* R: */ [BLOCK_JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1, 1}, - /* P: */ [BLOCK_JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 1, 1}, - /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 1, 0, 1}, - /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] =3D {1, 0, 0, 0, 0, 0}, + /* U, C, R, P, Y, W, E */ + /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0, 0, 0}, + /* C: */ [BLOCK_JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0, 0, 0}, + /* R: */ [BLOCK_JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1, 1, 1}, + /* P: */ [BLOCK_JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 1, 0, 1}, + /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 1, 0, 1, 1}, + /* W: */ [BLOCK_JOB_STATUS_WAITING] =3D {0, 0, 0, 0, 0, 0, 1}, + /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] =3D {1, 0, 0, 0, 0, 0, 0}, }; =20 enum BlockJobVerb { @@ -64,13 +65,13 @@ enum BlockJobVerb { }; =20 bool BlockJobVerb[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] =3D { - /* U, C, R, P, Y, E */ - [BLOCK_JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1, 0}, - [BLOCK_JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1, 0}, - [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0, 0}, - [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1, 0}, - [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1, 0}, - [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 1}, + /* U, C, R, P, Y, W, E */ + [BLOCK_JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1, 1, 0}, + [BLOCK_JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1, 0, 0}, + [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0, 0, 0}, + [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1, 0, 0}, + [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1, 0, 0}, + [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 0, 1}, }; =20 static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) @@ -789,6 +790,21 @@ static void block_job_event_completed(BlockJob *job, c= onst char *msg) &error_abort); } =20 +static void block_job_event_waiting(BlockJob *job) +{ + if (!job->manual) { + return; + } + block_job_state_transition(job, BLOCK_JOB_STATUS_WAITING); + if (block_job_is_internal(job)) { + return; + } + + qapi_event_send_block_job_waiting(job->driver->job_type, + job->id, + &error_abort); +} + static void block_job_event_concluded(BlockJob *job) { if (block_job_is_internal(job) || !job->manual) { @@ -925,6 +941,7 @@ void block_job_completed(BlockJob *job, int ret) } else if (ret < 0 || block_job_is_cancelled(job)) { block_job_completed_txn_abort(job); } else { + block_job_event_waiting(job); block_job_completed_txn_success(job); } } diff --git a/qapi/block-core.json b/qapi/block-core.json index f27c7054d2..f26fd1d8fd 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -966,7 +966,7 @@ ## { 'enum': 'BlockJobStatus', 'data': ['undefined', 'created', 'running', 'paused', 'ready', - 'concluded' ] } + 'waiting', 'concluded' ] } =20 ## # @BlockJobInfo: @@ -3867,6 +3867,29 @@ 'offset': 'int', 'speed' : 'int' } } =20 +## +# @BLOCK_JOB_WAITING: +# +# Emitted when a block job that is part of a transction has stopped work a= nd is +# waiting for other jobs in the transaction to reach the same state. +# +# @type: job type +# +# @id: The job identifier. +# +# Since: 2.12 +# +# Example: +# +# <- { "event": "BLOCK_JOB_WAITING", +# "data": { "id": "drive0", "type": "mirror" }, +# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } +# +## +{ 'event': 'BLOCK_JOB_WAITING', + 'data': { 'type' : 'BlockJobType', + 'id' : 'str' } } + ## # @PreallocMode: # --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019086377301.5482943620292; Fri, 26 Jan 2018 18:11:26 -0800 (PST) Received: from localhost ([::1]:43680 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFxl-0007qs-Hw for importer@patchew.org; Fri, 26 Jan 2018 21:11:25 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37410) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFsA-00019i-8V for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs8-0008To-Ri for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:38 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53774) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs4-0008Pd-TA; Fri, 26 Jan 2018 21:05:33 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3B3C080462; Sat, 27 Jan 2018 02:05:32 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 80B0F5457C; Sat, 27 Jan 2018 02:05:31 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:12 -0500 Message-Id: <20180127020515.27137-12-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Sat, 27 Jan 2018 02:05:32 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 11/14] blockjobs: add PENDING status and 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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" For jobs utilizing the new manual workflow, we intend to prohibit them from modifying the block graph until the management layer provides an explicit ACK via block-job-finalize to move the process forward. To distinguish this runstate from "ready" or "waiting," we add a new "pending" event. Valid transitions: Running -> Pending (non-transactional, non-mirror jobs) Ready -> Pending (non-transactional mirror jobs) Waiting -> Pending (transactional jobs) Invalid transitions: Waiting -> Concluded (no longer possible with this commit) Valid verbs: Cancel: A pending job may still be canceled. Signed-off-by: John Snow --- blockjob.c | 45 ++++++++++++++++++++++++++++++--------------- qapi/block-core.json | 26 +++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/blockjob.c b/blockjob.c index 6a3a630517..d31b65273c 100644 --- a/blockjob.c +++ b/blockjob.c @@ -44,14 +44,15 @@ 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, W, E */ - /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0, 0, 0}, - /* C: */ [BLOCK_JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0, 0, 0}, - /* R: */ [BLOCK_JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1, 1, 1}, - /* P: */ [BLOCK_JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 1, 0, 1}, - /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 1, 0, 1, 1}, - /* W: */ [BLOCK_JOB_STATUS_WAITING] =3D {0, 0, 0, 0, 0, 0, 1}, - /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] =3D {1, 0, 0, 0, 0, 0, 0}, + /* U, C, R, P, Y, W, D, E */ + /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] =3D {0, 1, 0, 0, 0, 0, 0, 0}, + /* C: */ [BLOCK_JOB_STATUS_CREATED] =3D {0, 0, 1, 0, 0, 0, 0, 0}, + /* R: */ [BLOCK_JOB_STATUS_RUNNING] =3D {0, 0, 0, 1, 1, 1, 1, 1}, + /* P: */ [BLOCK_JOB_STATUS_PAUSED] =3D {0, 0, 1, 0, 1, 0, 0, 1}, + /* Y: */ [BLOCK_JOB_STATUS_READY] =3D {0, 0, 0, 1, 0, 1, 1, 1}, + /* W: */ [BLOCK_JOB_STATUS_WAITING] =3D {0, 0, 0, 0, 0, 0, 1, 1}, + /* D: */ [BLOCK_JOB_STATUS_PENDING] =3D {0, 0, 0, 0, 0, 0, 0, 1}, + /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] =3D {1, 0, 0, 0, 0, 0, 0, 0}, }; =20 enum BlockJobVerb { @@ -65,13 +66,13 @@ enum BlockJobVerb { }; =20 bool BlockJobVerb[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] =3D { - /* U, C, R, P, Y, W, E */ - [BLOCK_JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1, 1, 0}, - [BLOCK_JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1, 0, 0}, - [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0, 0, 0}, - [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1, 0, 0}, - [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1, 0, 0}, - [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 0, 1}, + /* U, C, R, P, Y, W, D, E */ + [BLOCK_JOB_VERB_CANCEL] =3D {0, 1, 1, 1, 1, 1, 1, 0}, + [BLOCK_JOB_VERB_PAUSE] =3D {0, 1, 1, 1, 1, 0, 0, 0}, + [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0, 0, 0, 0}, + [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1, 0, 0, 0}, + [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1, 0, 0, 0}, + [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 0, 0, 1}, }; =20 static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) @@ -111,6 +112,7 @@ static void __attribute__((__constructor__)) block_job_= init(void) static void block_job_event_cancelled(BlockJob *job); static void block_job_event_completed(BlockJob *job, const char *msg); static void block_job_event_concluded(BlockJob *job); +static void block_job_event_pending(BlockJob *job); static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)); =20 /* Transactional group of block jobs */ @@ -805,6 +807,19 @@ static void block_job_event_waiting(BlockJob *job) &error_abort); } =20 +__attribute__((__unused__)) /* FIXME */ +static void block_job_event_pending(BlockJob *job) +{ + if (block_job_is_internal(job) || !job->manual) { + return; + } + block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING); + + qapi_event_send_block_job_pending(job->driver->job_type, + job->id, + &error_abort); +} + static void block_job_event_concluded(BlockJob *job) { if (block_job_is_internal(job) || !job->manual) { diff --git a/qapi/block-core.json b/qapi/block-core.json index f26fd1d8fd..1f2eb39810 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -966,7 +966,7 @@ ## { 'enum': 'BlockJobStatus', 'data': ['undefined', 'created', 'running', 'paused', 'ready', - 'waiting', 'concluded' ] } + 'waiting', 'pending', 'concluded' ] } =20 ## # @BlockJobInfo: @@ -3890,6 +3890,30 @@ 'data': { 'type' : 'BlockJobType', 'id' : 'str' } } =20 +## +# @BLOCK_JOB_PENDING: +# +# Emitted when a block job is awaiting explicit authorization to finalize = graph +# changes via @block-job-finalize. If this job is part of a transaction, i= t will +# not emit this event until the transaction has converged first. +# +# @type: job type +# +# @id: The job identifier. +# +# Since: 2.12 +# +# Example: +# +# <- { "event": "BLOCK_JOB_WAITING", +# "data": { "device": "drive0", "type": "mirror" }, +# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } +# +## +{ 'event': 'BLOCK_JOB_PENDING', + 'data': { 'type' : 'BlockJobType', + 'id' : 'str' } } + ## # @PreallocMode: # --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019573639858.65983806474; Fri, 26 Jan 2018 18:19:33 -0800 (PST) Received: from localhost ([::1]:44162 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efG5a-0006Ue-Uu for importer@patchew.org; Fri, 26 Jan 2018 21:19:30 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37437) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFsB-0001B0-4d for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:43 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFs9-0008UW-J3 for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:39 -0500 Received: from mx1.redhat.com ([209.132.183.28]:43398) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs5-0008Qf-U1; Fri, 26 Jan 2018 21:05:34 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3715255371; Sat, 27 Jan 2018 02:05:33 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5C8785457C; Sat, 27 Jan 2018 02:05:32 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:13 -0500 Message-Id: <20180127020515.27137-13-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Sat, 27 Jan 2018 02:05:33 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 12/14] blockjobs: add block-job-finalize 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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: John Snow --- block/trace-events | 1 + blockdev.c | 14 ++++++++++ blockjob.c | 72 +++++++++++++++++++++++++++++++++++++++-----= ---- include/block/blockjob.h | 17 ++++++++++++ qapi/block-core.json | 18 ++++++++++++ 5 files changed, 109 insertions(+), 13 deletions(-) diff --git a/block/trace-events b/block/trace-events index 8f61566770..d3be349489 100644 --- a/block/trace-events +++ b/block/trace-events @@ -46,6 +46,7 @@ qmp_block_job_cancel(void *job) "job %p" qmp_block_job_pause(void *job) "job %p" qmp_block_job_resume(void *job) "job %p" qmp_block_job_complete(void *job) "job %p" +qmp_block_job_finalize(void *job) "job %p" qmp_block_job_dismiss(void *job) "job %p" qmp_block_stream(void *bs, void *job) "bs %p job %p" =20 diff --git a/blockdev.c b/blockdev.c index 5e8edff322..d387ef6ec0 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3849,6 +3849,20 @@ void qmp_block_job_complete(const char *device, Erro= r **errp) aio_context_release(aio_context); } =20 +void qmp_block_job_finalize(const char *id, Error **errp) +{ + AioContext *aio_context; + BlockJob *job =3D find_block_job(id, &aio_context, errp); + + if (!job) { + return; + } + + trace_qmp_block_job_finalize(job); + block_job_finalize(job, errp); + aio_context_release(aio_context); +} + void qmp_block_job_dismiss(const char *id, Error **errp) { AioContext *aio_context; diff --git a/blockjob.c b/blockjob.c index d31b65273c..b8d6dd3bb4 100644 --- a/blockjob.c +++ b/blockjob.c @@ -61,6 +61,7 @@ enum BlockJobVerb { BLOCK_JOB_VERB_RESUME, BLOCK_JOB_VERB_SET_SPEED, BLOCK_JOB_VERB_COMPLETE, + BLOCK_JOB_VERB_FINALIZE, BLOCK_JOB_VERB_DISMISS, BLOCK_JOB_VERB__MAX }; @@ -72,6 +73,7 @@ bool BlockJobVerb[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__= MAX] =3D { [BLOCK_JOB_VERB_RESUME] =3D {0, 0, 0, 1, 0, 0, 0, 0}, [BLOCK_JOB_VERB_SET_SPEED] =3D {0, 1, 1, 1, 1, 0, 0, 0}, [BLOCK_JOB_VERB_COMPLETE] =3D {0, 0, 0, 0, 1, 0, 0, 0}, + [BLOCK_JOB_VERB_FINALIZE] =3D {0, 0, 0, 0, 0, 0, 1, 0}, [BLOCK_JOB_VERB_DISMISS] =3D {0, 0, 0, 0, 0, 0, 0, 1}, }; =20 @@ -459,6 +461,15 @@ static void block_job_completed_single(BlockJob *job) block_job_unref(job); } =20 +static void block_job_await_finalization(BlockJob *job) +{ + if (!job->manual) { + block_job_completed_single(job); + } else { + block_job_event_pending(job); + } +} + static void block_job_cancel_async(BlockJob *job) { if (job->iostatus !=3D BLOCK_DEVICE_IO_STATUS_OK) { @@ -558,6 +569,19 @@ static void block_job_completed_txn_abort(BlockJob *jo= b) block_job_txn_unref(txn); } =20 +static void block_job_txn_apply(BlockJobTxn *txn, void fn(BlockJob *)) +{ + AioContext *ctx; + BlockJob *job, *next; + + QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { + ctx =3D blk_get_aio_context(job->blk); + aio_context_acquire(ctx); + fn(job); + aio_context_release(ctx); + } +} + static void block_job_completed_txn_success(BlockJob *job) { AioContext *ctx; @@ -590,14 +614,9 @@ static void block_job_completed_txn_success(BlockJob *= job) } } =20 - /* We are the last completed job, commit the transaction. */ - QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { - ctx =3D blk_get_aio_context(other_job->blk); - aio_context_acquire(ctx); - assert(other_job->ret =3D=3D 0); - block_job_completed_single(other_job); - aio_context_release(ctx); - } + /* We are the last completed job, either commit the transaction + * or prepare for finalization via user intervention. */ + block_job_txn_apply(txn, block_job_await_finalization); } =20 /* Assumes the block_job_mutex is held */ @@ -606,6 +625,15 @@ static bool block_job_timer_pending(BlockJob *job) return timer_pending(&job->sleep_timer); } =20 +static void block_job_txn_completed(BlockJob *job, int ret) +{ + if (ret < 0 || block_job_is_cancelled(job)) { + block_job_completed_txn_abort(job); + } else { + block_job_completed_txn_success(job); + } +} + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) { Error *local_err =3D NULL; @@ -644,6 +672,27 @@ void block_job_complete(BlockJob *job, Error **errp) job->driver->complete(job, errp); } =20 +void block_job_finalize(BlockJob *job, Error **errp) +{ + assert(job->id); + if (!job->manual) { + error_setg(errp, "The block job '%s' was not started with " + "\'manual\': true, and so cannot be finalized as it wil= l" + "do so automatically upon finishing its task", job->id); + return; + } else if (job->status !=3D BLOCK_JOB_STATUS_PENDING) { + error_setg(errp, "The active block job '%s' is not yet awaiting " + "finalization and cannot be finalized", job->id); + return; + } + + if (!job->txn) { + block_job_completed_single(job); + } else { + block_job_txn_apply(job->txn, block_job_completed_single); + } +} + void block_job_dismiss(BlockJob **jobptr, Error **errp) { BlockJob *job =3D *jobptr; @@ -807,7 +856,6 @@ static void block_job_event_waiting(BlockJob *job) &error_abort); } =20 -__attribute__((__unused__)) /* FIXME */ static void block_job_event_pending(BlockJob *job) { if (block_job_is_internal(job) || !job->manual) { @@ -952,12 +1000,10 @@ void block_job_completed(BlockJob *job, int ret) job->completed =3D true; job->ret =3D ret; if (!job->txn) { - block_job_completed_single(job); - } else if (ret < 0 || block_job_is_cancelled(job)) { - block_job_completed_txn_abort(job); + block_job_await_finalization(job); } else { block_job_event_waiting(job); - block_job_completed_txn_success(job); + block_job_txn_completed(job, ret); } } =20 diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 5f73fc8831..188853ca77 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -244,6 +244,23 @@ void block_job_cancel(BlockJob *job); */ void block_job_complete(BlockJob *job, Error **errp); =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. diff --git a/qapi/block-core.json b/qapi/block-core.json index 1f2eb39810..bd4458bf57 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2219,6 +2219,24 @@ ## { 'command': 'block-job-dismiss', 'data': { 'id': 'str' } } =20 +## +# @block-job-finalize: +# +# Once a job that has manual=3Dtrue reaches the pending state, it can be +# instructed to finalize any graph changes and do any necessary cleanup +# via this command. +# For jobs in a transaction, instructing one job to finalize will force +# ALL jobs in the transaction to finalize, so it is only necessary to inst= ruct +# a single member job to finalize. +# +# @id: The job identifier. +# +# Returns: Nothing on success +# +# Since: 2.12 +## +{ 'command': 'block-job-finalize', 'data': { 'id': 'str' } } + ## # @BlockdevDiscardOptions: # --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019496453880.6774462985462; Fri, 26 Jan 2018 18:18:16 -0800 (PST) Received: from localhost ([::1]:44042 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efG4N-0005Y1-KA for importer@patchew.org; Fri, 26 Jan 2018 21:18:15 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37457) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFsC-0001CC-0X for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFsA-0008VS-DF for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:40 -0500 Received: from mx1.redhat.com ([209.132.183.28]:48118) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs6-0008RN-P2; Fri, 26 Jan 2018 21:05:35 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 12B6846269; Sat, 27 Jan 2018 02:05:34 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5860E5457C; Sat, 27 Jan 2018 02:05:33 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:14 -0500 Message-Id: <20180127020515.27137-14-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Sat, 27 Jan 2018 02:05:34 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 13/14] blockjobs: Expose manual property 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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" Expose the "manual" property via QAPI for the backup-related jobs. As of this commit, this allows the management API to request the "concluded" and "dismiss" semantics for backup jobs. Signed-off-by: John Snow --- blockdev.c | 14 ++++++++++---- include/block/block_int.h | 3 +++ qapi/block-core.json | 32 ++++++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/blockdev.c b/blockdev.c index d387ef6ec0..e7c3fc0607 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3281,6 +3281,9 @@ static BlockJob *do_drive_backup(DriveBackup *backup,= BlockJobTxn *txn, if (!backup->has_job_id) { backup->job_id =3D NULL; } + if (!backup->has_manual) { + backup->manual =3D false; + } if (!backup->has_compress) { backup->compress =3D false; } @@ -3373,8 +3376,8 @@ static BlockJob *do_drive_backup(DriveBackup *backup,= BlockJobTxn *txn, } } =20 - job =3D backup_job_create(backup->job_id, false, bs, target_bs, backup= ->speed, - backup->sync, bmap, backup->compress, + job =3D backup_job_create(backup->job_id, backup->manual, bs, target_b= s, + backup->speed, backup->sync, bmap, backup->com= press, backup->on_source_error, backup->on_target_err= or, BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err= ); bdrv_unref(target_bs); @@ -3424,6 +3427,9 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, = BlockJobTxn *txn, if (!backup->has_job_id) { backup->job_id =3D NULL; } + if (!backup->has_manual) { + backup->manual =3D false; + } if (!backup->has_compress) { backup->compress =3D false; } @@ -3452,8 +3458,8 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, = BlockJobTxn *txn, goto out; } } - job =3D backup_job_create(backup->job_id, false, bs, target_bs, backup= ->speed, - backup->sync, NULL, backup->compress, + job =3D backup_job_create(backup->job_id, backup->manual, bs, target_b= s, + backup->speed, backup->sync, NULL, backup->com= press, backup->on_source_error, backup->on_target_err= or, BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err= ); if (local_err !=3D NULL) { diff --git a/include/block/block_int.h b/include/block/block_int.h index 08f5046c63..d91f50ca60 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -965,6 +965,9 @@ void mirror_start(const char *job_id, BlockDriverState = *bs, * backup_job_create: * @job_id: The id of the newly-created job, or %NULL to use the * device name of @bs. + * @manual: Whether or not this job requires manual intervention to transi= tion + * from "PENDING" state to "CONCLUDED" state, and again, manual + * intervention to dismiss CONCLUDED jobs. * @bs: Block device to operate on. * @target: Block device to write to. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. diff --git a/qapi/block-core.json b/qapi/block-core.json index bd4458bf57..d8d82404da 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1119,6 +1119,16 @@ # @job-id: identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # +# @manual: True to use an expanded, more explicit job control flow. +# Jobs may transition from a running state to a pending state, +# where they must be instructed to complete manually via +# block-job-finalize. +# Jobs belonging to a transaction must either all or all not use = this +# setting. Once a transaction reaches a pending state, issuing the +# finalize command to any one job in the transaction is sufficient +# to finalize the entire transaction. +# (Since 2.12) +# # @device: the device name or node-name of a root node which should be cop= ied. # # @target: the target of the new image. If the file exists, or if it @@ -1159,9 +1169,10 @@ # Since: 1.6 ## { 'struct': 'DriveBackup', - 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', - '*format': 'str', 'sync': 'MirrorSyncMode', '*mode': 'NewImage= Mode', - '*speed': 'int', '*bitmap': 'str', '*compress': 'bool', + 'data': { '*job-id': 'str', '*manual': 'bool', 'device': 'str', + 'target': 'str', '*format': 'str', 'sync': 'MirrorSyncMode', + '*mode': 'NewImageMode', '*speed': 'int', + '*bitmap': 'str', '*compress': 'bool', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } =20 @@ -1171,6 +1182,16 @@ # @job-id: identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # +# @manual: True to use an expanded, more explicit job control flow. +# Jobs may transition from a running state to a pending state, +# where they must be instructed to complete manually via +# block-job-finalize. +# Jobs belonging to a transaction must either all or all not use = this +# setting. Once a transaction reaches a pending state, issuing the +# finalize command to any one job in the transaction is sufficient +# to finalize the entire transaction. +# (Since 2.12) +# # @device: the device name or node-name of a root node which should be cop= ied. # # @target: the device name or node-name of the backup target node. @@ -1200,9 +1221,8 @@ # Since: 2.3 ## { 'struct': 'BlockdevBackup', - 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', - 'sync': 'MirrorSyncMode', - '*speed': 'int', + 'data': { '*job-id': 'str', '*manual': 'bool', 'device': 'str', + 'target': 'str', 'sync': 'MirrorSyncMode', '*speed': 'int', '*compress': 'bool', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } --=20 2.14.3 From nobody Tue Apr 30 09:06:45 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517019698034405.3927972488326; Fri, 26 Jan 2018 18:21:38 -0800 (PST) Received: from localhost ([::1]:44293 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efG7d-0007zD-A3 for importer@patchew.org; Fri, 26 Jan 2018 21:21:37 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37480) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1efFsD-0001CG-Av for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:44 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1efFsB-0008WO-OA for qemu-devel@nongnu.org; Fri, 26 Jan 2018 21:05:41 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53800) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1efFs7-0008Rw-KF; Fri, 26 Jan 2018 21:05:35 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E363780462; Sat, 27 Jan 2018 02:05:34 +0000 (UTC) Received: from probe.bos.redhat.com (dhcp-17-231.bos.redhat.com [10.18.17.231]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3571F5457C; Sat, 27 Jan 2018 02:05:34 +0000 (UTC) From: John Snow To: qemu-block@nongnu.org Date: Fri, 26 Jan 2018 21:05:15 -0500 Message-Id: <20180127020515.27137-15-jsnow@redhat.com> In-Reply-To: <20180127020515.27137-1-jsnow@redhat.com> References: <20180127020515.27137-1-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Sat, 27 Jan 2018 02:05:34 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v3 14/14] iotests: test manual job dismissal 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, John Snow , pkrempa@redhat.com, jtc@redhat.com, qemu-devel@nongnu.org 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" RFC: The error returned by a job creation command when that device already has a job attached has become misleading; "Someone should do something about that!" Signed-off-by: John Snow --- tests/qemu-iotests/056 | 241 +++++++++++++++++++++++++++++++++++++++++= ++++ tests/qemu-iotests/056.out | 4 +- 2 files changed, 243 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 index 04f2c3c841..846e0419d0 100755 --- a/tests/qemu-iotests/056 +++ b/tests/qemu-iotests/056 @@ -29,6 +29,26 @@ backing_img =3D os.path.join(iotests.test_dir, 'backing.= img') test_img =3D os.path.join(iotests.test_dir, 'test.img') target_img =3D os.path.join(iotests.test_dir, 'target.img') =20 +def img_create(img, fmt=3Diotests.imgfmt, size=3D'64M', **kwargs): + fullname =3D os.path.join(iotests.test_dir, '%s.%s' % (img, fmt)) + optargs =3D [] + for k,v in kwargs.iteritems(): + optargs =3D optargs + ['-o', '%s=3D%s' % (k,v)] + args =3D ['create', '-f', fmt] + optargs + [fullname, size] + iotests.qemu_img(*args) + return fullname + +def try_remove(img): + try: + os.remove(img) + except OSError: + pass + +def io_write_patterns(img, patterns): + for pattern in patterns: + iotests.qemu_io('-c', 'write -P%s %s %s' % pattern, img) + + class TestSyncModesNoneAndTop(iotests.QMPTestCase): image_len =3D 64 * 1024 * 1024 # MB =20 @@ -108,5 +128,226 @@ class TestBeforeWriteNotifier(iotests.QMPTestCase): event =3D self.cancel_and_wait() self.assert_qmp(event, 'data/type', 'backup') =20 +class BackupTest(iotests.QMPTestCase): + def setUp(self): + self.vm =3D iotests.VM() + self.test_img =3D img_create('test') + self.dest_img =3D img_create('dest') + self.vm.add_drive(self.test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + try_remove(self.test_img) + try_remove(self.dest_img) + + def hmp_io_writes(self, drive, patterns): + for pattern in patterns: + self.vm.hmp_qemu_io(drive, 'write -P%s %s %s' % pattern) + self.vm.hmp_qemu_io(drive, 'flush') + + def qmp_job_pending_wait(self, device): + event =3D self.vm.event_wait(name=3D"BLOCK_JOB_PENDING", + match=3D{'data': {'id': device}}) + self.assertNotEqual(event, None) + res =3D self.vm.qmp("block-job-finalize", id=3Ddevice) + self.assert_qmp(res, 'return', {}) + + def qmp_backup_and_wait(self, cmd=3D'drive-backup', serror=3DNone, + aerror=3DNone, **kwargs): + if not self.qmp_backup(cmd, serror, **kwargs): + return False + if 'manual' in kwargs and kwargs['manual']: + self.qmp_job_pending_wait(kwargs['device']) + return self.qmp_backup_wait(kwargs['device'], aerror) + + def qmp_backup(self, cmd=3D'drive-backup', + error=3DNone, **kwargs): + self.assertTrue('device' in kwargs) + res =3D self.vm.qmp(cmd, **kwargs) + if error: + self.assert_qmp(res, 'error/desc', error) + return False + self.assert_qmp(res, 'return', {}) + return True + + def qmp_backup_wait(self, device, error=3DNone): + event =3D self.vm.event_wait(name=3D"BLOCK_JOB_COMPLETED", + match=3D{'data': {'device': device}}) + self.assertNotEqual(event, None) + try: + failure =3D self.dictpath(event, 'data/error') + except AssertionError: + # Backup succeeded. + self.assert_qmp(event, 'data/offset', event['data']['len']) + return True + else: + # Failure. + self.assert_qmp(event, 'data/error', qerror) + return False + + def test_dismiss_false(self): + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + self.qmp_backup_and_wait(device=3D'drive0', format=3Diotests.imgfm= t, + sync=3D'full', target=3Dself.dest_img, ma= nual=3DFalse) + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + + def test_dismiss_true(self): + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + self.qmp_backup_and_wait(device=3D'drive0', format=3Diotests.imgfm= t, + sync=3D'full', target=3Dself.dest_img, ma= nual=3DTrue) + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return[0]/status', 'concluded') + res =3D self.vm.qmp('block-job-dismiss', id=3D'drive0') + self.assert_qmp(res, 'return', {}) + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + + def test_dismiss_bad_id(self): + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + res =3D self.vm.qmp('block-job-dismiss', id=3D'foobar') + self.assert_qmp(res, 'error/class', 'DeviceNotActive') + + def test_dismiss_collision(self): + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + self.qmp_backup_and_wait(device=3D'drive0', format=3Diotests.imgfm= t, + sync=3D'full', target=3Dself.dest_img, ma= nual=3DTrue) + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return[0]/status', 'concluded') + # Leave zombie job un-dismissed, observe a failure: + res =3D self.qmp_backup_and_wait(serror=3D'Need a root block node', + device=3D'drive0', format=3Diotests= .imgfmt, + sync=3D'full', target=3Dself.dest_i= mg, + manual=3DTrue) + self.assertEqual(res, False) + # OK, dismiss the zombie. + res =3D self.vm.qmp('block-job-dismiss', id=3D'drive0') + self.assert_qmp(res, 'return', {}) + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + # Ensure it's really gone. + self.qmp_backup_and_wait(device=3D'drive0', format=3Diotests.imgfm= t, + sync=3D'full', target=3Dself.dest_img, ma= nual=3DTrue) + + def test_dismiss_premature(self): + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + # Give blkdebug something to chew on + self.hmp_io_writes('drive0', + (('0x9a', 0, 512), + ('0x55', '8M', '352k'), + ('0x78', '15872k', '1M'))) + # Add destination node via blkdebug + res =3D self.vm.qmp('blockdev-add', + node_name=3D'target0', + driver=3Diotests.imgfmt, + file=3D{ + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': self.dest_img + }, + 'inject-error': [{ + 'event': 'write_aio', + 'errno': 5, + 'immediately': False, + 'once': True + }], + }) + self.assert_qmp(res, 'return', {}) + + res =3D self.qmp_backup(cmd=3D'blockdev-backup', + device=3D'drive0', target=3D'target0', + on_target_error=3D'stop', + sync=3D'full', + manual=3DTrue) + self.assertTrue(res) + event =3D self.vm.event_wait(name=3D"BLOCK_JOB_ERROR", + match=3D{'data': {'device': 'drive0'}}) + self.assertNotEqual(event, None) + # OK, job should be wedged + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return[0]/status', 'paused') + res =3D self.vm.qmp('block-job-dismiss', id=3D'drive0') + self.assert_qmp(res, 'error/desc', + "The active block job 'drive0', status: 'paused', = has not yet concluded, and cannot be dismissed yet") + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return[0]/status', 'paused') + # OK, unstick job and move forward. + res =3D self.vm.qmp('block-job-resume', device=3D'drive0') + self.assert_qmp(res, 'return', {}) + # Job should now be pending... + self.qmp_job_pending_wait('drive0') + # And now we need to wait for it to conclude; + res =3D self.qmp_backup_wait(device=3D'drive0') + self.assertTrue(res) + # Job should now be languishing: + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return[0]/status', 'concluded') + res =3D self.vm.qmp('block-job-dismiss', id=3D'drive0') + self.assert_qmp(res, 'return', {}) + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + + def test_dismiss_erroneous(self): + '''Same as above test, but manual is set to False.''' + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + # Give blkdebug something to chew on + self.hmp_io_writes('drive0', + (('0x9a', 0, 512), + ('0x55', '8M', '352k'), + ('0x78', '15872k', '1M'))) + # Add destination node via blkdebug + res =3D self.vm.qmp('blockdev-add', + node_name=3D'target0', + driver=3Diotests.imgfmt, + file=3D{ + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': self.dest_img + }, + 'inject-error': [{ + 'event': 'write_aio', + 'errno': 5, + 'immediately': False, + 'once': True + }], + }) + self.assert_qmp(res, 'return', {}) + + res =3D self.qmp_backup(cmd=3D'blockdev-backup', + device=3D'drive0', target=3D'target0', + on_target_error=3D'stop', + sync=3D'full', + manual=3DFalse) + self.assertTrue(res) + event =3D self.vm.event_wait(name=3D"BLOCK_JOB_ERROR", + match=3D{'data': {'device': 'drive0'}}) + self.assertNotEqual(event, None) + # OK, job should be wedged + res =3D self.vm.qmp('query-block-jobs') + # NB: No 'status' field when manual =3D false. + self.assert_qmp(res, 'return[0]/paused', True) + res =3D self.vm.qmp('block-job-dismiss', id=3D'drive0') + self.assert_qmp(res, 'error/desc', + "The active block job 'drive0' was not started wit= h 'manual': true, and so cannot be dismissed as it will clean up after itse= lf automatically") + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return[0]/paused', True) + # OK, unstick job and move forward. + res =3D self.vm.qmp('block-job-resume', device=3D'drive0') + self.assert_qmp(res, 'return', {}) + res =3D self.qmp_backup_wait(device=3D'drive0') + self.assertTrue(res) + # Job should now be gone: + res =3D self.vm.qmp('query-block-jobs') + self.assert_qmp(res, 'return', []) + if __name__ =3D=3D '__main__': iotests.main(supported_fmts=3D['qcow2', 'qed']) diff --git a/tests/qemu-iotests/056.out b/tests/qemu-iotests/056.out index 8d7e996700..dae404e278 100644 --- a/tests/qemu-iotests/056.out +++ b/tests/qemu-iotests/056.out @@ -1,5 +1,5 @@ -... +......... ---------------------------------------------------------------------- -Ran 3 tests +Ran 9 tests =20 OK --=20 2.14.3