From nobody Thu May 2 17:53:52 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 1501595630363826.597581992961; Tue, 1 Aug 2017 06:53:50 -0700 (PDT) Received: from localhost ([::1]:42667 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXcL-00080f-19 for importer@patchew.org; Tue, 01 Aug 2017 09:53:49 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60400) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXZ1-0005lo-Uv for qemu-devel@nongnu.org; Tue, 01 Aug 2017 09:50:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dcXYx-0005Je-6S for qemu-devel@nongnu.org; Tue, 01 Aug 2017 09:50:24 -0400 Received: from smtp1.ntua.gr ([2001:648:2000:de::183]:48064) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXYu-000587-8H; Tue, 01 Aug 2017 09:50:16 -0400 Received: from mail.ntua.gr ([IPv6:2a02:587:8020:2800:cd94:9845:8007:a6e4]) (authenticated bits=0) by smtp1.ntua.gr (8.15.2/8.15.2) with ESMTPSA id v71Dnar6012811 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 1 Aug 2017 16:49:36 +0300 (EEST) (envelope-from el13635@mail.ntua.gr) X-Authentication-Warning: smtp1.ntua.gr: Host [IPv6:2a02:587:8020:2800:cd94:9845:8007:a6e4] claimed to be mail.ntua.gr From: Manos Pitsidianakis To: qemu-devel Date: Tue, 1 Aug 2017 16:49:05 +0300 Message-Id: <20170801134907.31253-2-el13635@mail.ntua.gr> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170801134907.31253-1-el13635@mail.ntua.gr> References: <20170801134907.31253-1-el13635@mail.ntua.gr> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:648:2000:de::183 Subject: [Qemu-devel] [PATCH 1/3] block: add options parameter to bdrv_new_open_driver() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Alberto Garcia , qemu-block , Stefan Hajnoczi 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" Allow passing a QDict *options parameter to bdrv_new_open_driver() so that it can be used if a driver needs it upon creation. The previous behaviour (empty bs->options and bs->explicit_options) remains when options is NULL. Signed-off-by: Manos Pitsidianakis --- block.c | 16 +++++++++++++--- block/commit.c | 4 ++-- block/mirror.c | 2 +- block/vvfat.c | 2 +- include/block/block.h | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index 37e72b7a96..886a457ab0 100644 --- a/block.c +++ b/block.c @@ -1149,16 +1149,26 @@ free_and_fail: return ret; } =20 +/* + * If options is not NULL it is cloned (which adds another reference to the + * option entries). If the call to bdrv_new_open_driver() is successful, t= he + * caller should unref options to pass ownership. + * */ BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_= name, - int flags, Error **errp) + int flags, QDict *options, Error **= errp) { BlockDriverState *bs; int ret; =20 bs =3D bdrv_new(); bs->open_flags =3D flags; - bs->explicit_options =3D qdict_new(); - bs->options =3D qdict_new(); + if (options) { + bs->explicit_options =3D qdict_clone_shallow(options); + bs->options =3D qdict_clone_shallow(options); + } else { + bs->explicit_options =3D qdict_new(); + bs->options =3D qdict_new(); + } bs->opaque =3D NULL; =20 update_options_from_flags(bs->options, flags); diff --git a/block/commit.c b/block/commit.c index c7857c3321..539e23c3f8 100644 --- a/block/commit.c +++ b/block/commit.c @@ -342,7 +342,7 @@ void commit_start(const char *job_id, BlockDriverState = *bs, /* Insert commit_top block node above top, so we can block consistent = read * on the backing chain below it */ commit_top_bs =3D bdrv_new_open_driver(&bdrv_commit_top, filter_node_n= ame, 0, - errp); + NULL, errp); if (commit_top_bs =3D=3D NULL) { goto fail; } @@ -494,7 +494,7 @@ int bdrv_commit(BlockDriverState *bs) backing_file_bs =3D backing_bs(bs); =20 commit_top_bs =3D bdrv_new_open_driver(&bdrv_commit_top, NULL, BDRV_O_= RDWR, - &local_err); + NULL, &local_err); if (commit_top_bs =3D=3D NULL) { error_report_err(local_err); goto ro_cleanup; diff --git a/block/mirror.c b/block/mirror.c index c9a6a3ca86..e1a160e6ea 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1164,7 +1164,7 @@ static void mirror_start_job(const char *job_id, Bloc= kDriverState *bs, * reads on the top, while disabling it in the intermediate nodes, and= make * the backing chain writable. */ mirror_top_bs =3D bdrv_new_open_driver(&bdrv_mirror_top, filter_node_n= ame, - BDRV_O_RDWR, errp); + BDRV_O_RDWR, NULL, errp); if (mirror_top_bs =3D=3D NULL) { return; } diff --git a/block/vvfat.c b/block/vvfat.c index a9e207f7f0..6c59473baf 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3194,7 +3194,7 @@ static int enable_write_target(BlockDriverState *bs, = Error **errp) #endif =20 backing =3D bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALL= OW_RDWR, - &error_abort); + NULL, &error_abort); *(void**) backing->opaque =3D s; =20 bdrv_set_backing_hd(s->bs, backing, &error_abort); diff --git a/include/block/block.h b/include/block/block.h index 34770bb33a..020289a37d 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -263,7 +263,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict = *parent_options, BlockDriverState *bdrv_open(const char *filename, const char *reference, QDict *options, int flags, Error **errp); BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_= name, - int flags, Error **errp); + int flags, QDict *options, Error **= errp); BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs, QDict *options, int flags); --=20 2.11.0 From nobody Thu May 2 17:53:52 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 1501595511106473.45296049967965; Tue, 1 Aug 2017 06:51:51 -0700 (PDT) Received: from localhost ([::1]:42659 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXaP-0006id-5a for importer@patchew.org; Tue, 01 Aug 2017 09:51:49 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60345) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXYx-0005hq-Vc for qemu-devel@nongnu.org; Tue, 01 Aug 2017 09:50:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dcXYw-0005JQ-Vw for qemu-devel@nongnu.org; Tue, 01 Aug 2017 09:50:20 -0400 Received: from smtp1.ntua.gr ([2001:648:2000:de::183]:48065) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXYu-00058L-83; Tue, 01 Aug 2017 09:50:16 -0400 Received: from mail.ntua.gr ([IPv6:2a02:587:8020:2800:cd94:9845:8007:a6e4]) (authenticated bits=0) by smtp1.ntua.gr (8.15.2/8.15.2) with ESMTPSA id v71DncxY012823 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 1 Aug 2017 16:49:38 +0300 (EEST) (envelope-from el13635@mail.ntua.gr) X-Authentication-Warning: smtp1.ntua.gr: Host [IPv6:2a02:587:8020:2800:cd94:9845:8007:a6e4] claimed to be mail.ntua.gr From: Manos Pitsidianakis To: qemu-devel Date: Tue, 1 Aug 2017 16:49:06 +0300 Message-Id: <20170801134907.31253-3-el13635@mail.ntua.gr> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170801134907.31253-1-el13635@mail.ntua.gr> References: <20170801134907.31253-1-el13635@mail.ntua.gr> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:648:2000:de::183 Subject: [Qemu-devel] [PATCH 2/3] block: skip implicit nodes in snapshots, blockjobs 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: Kevin Wolf , Alberto Garcia , qemu-block , Stefan Hajnoczi 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" Implicit filter nodes added at the top of nodes can interfere with block jobs. This is not a problem when they are added by other jobs since adding another job will issue a QERR_DEVICE_IN_USE, but it can happen in the next commit which introduces an implicitly created throttle filter node below BlockBackend, which we want to be skipped during automatic operations on the graph since the user does not necessarily know about their existence. Signed-off-by: Manos Pitsidianakis --- block.c | 17 +++++++++++++++++ blockdev.c | 12 ++++++++++++ include/block/block_int.h | 2 ++ 3 files changed, 31 insertions(+) diff --git a/block.c b/block.c index 886a457ab0..9ebdba28b0 100644 --- a/block.c +++ b/block.c @@ -4947,3 +4947,20 @@ bool bdrv_can_store_new_dirty_bitmap(BlockDriverStat= e *bs, const char *name, =20 return drv->bdrv_can_store_new_dirty_bitmap(bs, name, granularity, err= p); } + +/* Get first non-implicit node down a bs chain. */ +BlockDriverState *bdrv_get_first_non_implicit(BlockDriverState *bs) +{ + if (!bs) { + return NULL; + } + + if (!bs->implicit) { + return bs; + } + + /* at this point bs is implicit and must have a child */ + assert(bs->file); + + return bdrv_get_first_non_implicit(bs->file->bs); +} diff --git a/blockdev.c b/blockdev.c index 23475abb72..d903a23786 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1664,6 +1664,9 @@ static void external_snapshot_prepare(BlkActionState = *common, return; } =20 + /* Skip implicit filter nodes */ + state->old_bs =3D bdrv_get_first_non_implicit(state->old_bs); + /* Acquire AioContext now so any threads operating on old_bs stop */ state->aio_context =3D bdrv_get_aio_context(state->old_bs); aio_context_acquire(state->aio_context); @@ -3095,6 +3098,9 @@ void qmp_block_commit(bool has_job_id, const char *jo= b_id, const char *device, return; } =20 + /* Skip implicit filter nodes */ + bs =3D bdrv_get_first_non_implicit(bs); + aio_context =3D bdrv_get_aio_context(bs); aio_context_acquire(aio_context); =20 @@ -3209,6 +3215,9 @@ static BlockJob *do_drive_backup(DriveBackup *backup,= BlockJobTxn *txn, return NULL; } =20 + /* Skip implicit filter nodes */ + bs =3D bdrv_get_first_non_implicit(bs); + aio_context =3D bdrv_get_aio_context(bs); aio_context_acquire(aio_context); =20 @@ -3484,6 +3493,9 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) return; } =20 + /* Skip implicit filter nodes */ + bs =3D bdrv_get_first_non_implicit(bs); + aio_context =3D bdrv_get_aio_context(bs); aio_context_acquire(aio_context); =20 diff --git a/include/block/block_int.h b/include/block/block_int.h index d4f4ea7584..9eeae490f0 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -981,4 +981,6 @@ void bdrv_dec_in_flight(BlockDriverState *bs); =20 void blockdev_close_all_bdrv_states(void); =20 +BlockDriverState *bdrv_get_first_non_implicit(BlockDriverState *bs); + #endif /* BLOCK_INT_H */ --=20 2.11.0 From nobody Thu May 2 17:53:52 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 1501595861059262.49725342553893; Tue, 1 Aug 2017 06:57:41 -0700 (PDT) Received: from localhost ([::1]:42691 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXg3-0002dy-1v for importer@patchew.org; Tue, 01 Aug 2017 09:57:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60392) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXZ1-0005ky-4l for qemu-devel@nongnu.org; Tue, 01 Aug 2017 09:50:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dcXYy-0005Mf-U7 for qemu-devel@nongnu.org; Tue, 01 Aug 2017 09:50:23 -0400 Received: from smtp1.ntua.gr ([2001:648:2000:de::183]:48069) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dcXYs-0005Cn-Me; Tue, 01 Aug 2017 09:50:15 -0400 Received: from mail.ntua.gr ([IPv6:2a02:587:8020:2800:cd94:9845:8007:a6e4]) (authenticated bits=0) by smtp1.ntua.gr (8.15.2/8.15.2) with ESMTPSA id v71DndT1012831 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 1 Aug 2017 16:49:40 +0300 (EEST) (envelope-from el13635@mail.ntua.gr) X-Authentication-Warning: smtp1.ntua.gr: Host [IPv6:2a02:587:8020:2800:cd94:9845:8007:a6e4] claimed to be mail.ntua.gr From: Manos Pitsidianakis To: qemu-devel Date: Tue, 1 Aug 2017 16:49:07 +0300 Message-Id: <20170801134907.31253-4-el13635@mail.ntua.gr> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170801134907.31253-1-el13635@mail.ntua.gr> References: <20170801134907.31253-1-el13635@mail.ntua.gr> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:648:2000:de::183 Subject: [Qemu-devel] [PATCH 3/3] block: remove legacy I/O throttling 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: Kevin Wolf , Alberto Garcia , qemu-block , Stefan Hajnoczi Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This commit removes all I/O throttling from block/block-backend.c. In order to support the existing interface, it is changed to use the block/throttle.c filter driver. The throttle filter node that is created by the legacy interface is stored in a 'throttle_node' field in the BlockBackendPublic of the device. The legacy throttle node is managed by the legacy interface completely. More advanced configurations with the filter drive are possible using the QMP API, but these will be ignored by the legacy interface. Signed-off-by: Manos Pitsidianakis --- block.c | 8 +++ block/block-backend.c | 149 +++++++++++++++++++++++++-----------= ---- block/qapi.c | 14 ++-- block/throttle.c | 8 +++ blockdev.c | 55 +++++++++++---- include/block/block_int.h | 13 ++++ include/block/throttle-groups.h | 2 + include/sysemu/block-backend.h | 8 +-- tests/test-throttle.c | 15 ++-- 9 files changed, 186 insertions(+), 86 deletions(-) diff --git a/block.c b/block.c index 9ebdba28b0..c6aad25286 100644 --- a/block.c +++ b/block.c @@ -1975,6 +1975,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *c= hild_bs, child =3D g_new(BdrvChild, 1); *child =3D (BdrvChild) { .bs =3D NULL, + .parent_bs =3D NULL, .name =3D g_strdup(child_name), .role =3D child_role, .perm =3D perm, @@ -2009,6 +2010,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent= _bs, if (child =3D=3D NULL) { return NULL; } + child->parent_bs =3D parent_bs; =20 QLIST_INSERT_HEAD(&parent_bs->children, child, next); return child; @@ -3729,6 +3731,12 @@ const char *bdrv_get_parent_name(const BlockDriverSt= ate *bs) return name; } } + if (c->parent_bs && c->parent_bs->implicit) { + name =3D bdrv_get_parent_name(c->parent_bs); + if (name && *name) { + return name; + } + } } =20 return NULL; diff --git a/block/block-backend.c b/block/block-backend.c index df0200fc49..45f45efee9 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -15,6 +15,7 @@ #include "block/block_int.h" #include "block/blockjob.h" #include "block/throttle-groups.h" +#include "qemu/throttle-options.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" #include "qapi-event.h" @@ -282,8 +283,8 @@ static void blk_delete(BlockBackend *blk) assert(!blk->refcnt); assert(!blk->name); assert(!blk->dev); - if (blk->public.throttle_group_member.throttle_state) { - blk_io_limits_disable(blk); + if (blk->public.throttle_node) { + blk_io_limits_disable(blk, &error_abort); } if (blk->root) { blk_remove_bs(blk); @@ -593,13 +594,7 @@ BlockBackend *blk_by_public(BlockBackendPublic *public) */ void blk_remove_bs(BlockBackend *blk) { - ThrottleTimers *tt; - notifier_list_notify(&blk->remove_bs_notifiers, blk); - if (blk->public.throttle_group_member.throttle_state) { - tt =3D &blk->public.throttle_group_member.throttle_timers; - throttle_timers_detach_aio_context(tt); - } =20 blk_update_root_state(blk); =20 @@ -620,12 +615,6 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState = *bs, Error **errp) bdrv_ref(bs); =20 notifier_list_notify(&blk->insert_bs_notifiers, blk); - if (blk->public.throttle_group_member.throttle_state) { - throttle_timers_attach_aio_context( - &blk->public.throttle_group_member.throttle_timers, - bdrv_get_aio_context(bs)); - } - return 0; } =20 @@ -983,13 +972,6 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int6= 4_t offset, } =20 bdrv_inc_in_flight(bs); - - /* throttling disk I/O */ - if (blk->public.throttle_group_member.throttle_state) { - throttle_group_co_io_limits_intercept(&blk->public.throttle_group_= member, - bytes, false); - } - ret =3D bdrv_co_preadv(blk->root, offset, bytes, qiov, flags); bdrv_dec_in_flight(bs); return ret; @@ -1010,11 +992,6 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, in= t64_t offset, } =20 bdrv_inc_in_flight(bs); - /* throttling disk I/O */ - if (blk->public.throttle_group_member.throttle_state) { - throttle_group_co_io_limits_intercept(&blk->public.throttle_group_= member, - bytes, true); - } =20 if (!blk->enable_write_cache) { flags |=3D BDRV_REQ_FUA; @@ -1682,16 +1659,9 @@ static AioContext *blk_aiocb_get_aio_context(BlockAI= OCB *acb) void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) { BlockDriverState *bs =3D blk_bs(blk); - ThrottleGroupMember *tgm =3D &blk->public.throttle_group_member; =20 if (bs) { - if (tgm->throttle_state) { - throttle_group_detach_aio_context(tgm); - } bdrv_set_aio_context(bs, new_context); - if (tgm->throttle_state) { - throttle_group_attach_aio_context(tgm, new_context); - } } } =20 @@ -1909,45 +1879,110 @@ int blk_commit_all(void) /* throttling disk I/O limits */ void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg) { - throttle_group_config(&blk->public.throttle_group_member, cfg); + assert(blk->public.throttle_node); + throttle_group_config(throttle_get_tgm(blk->public.throttle_node), cfg= ); } =20 -void blk_io_limits_disable(BlockBackend *blk) +void blk_io_limits_disable(BlockBackend *blk, Error **errp) { - assert(blk->public.throttle_group_member.throttle_state); - bdrv_drained_begin(blk_bs(blk)); - throttle_group_unregister_tgm(&blk->public.throttle_group_member); - bdrv_drained_end(blk_bs(blk)); + BlockDriverState *bs, *throttle_node; + + throttle_node =3D blk_get_public(blk)->throttle_node; + + assert(throttle_node && throttle_node->refcnt =3D=3D 1); + + bs =3D throttle_node->file->bs; + blk_get_public(blk)->throttle_node =3D NULL; + + /* ref throttle_node's child bs so that it isn't lost when throttle_no= de is + * destroyed */ + bdrv_ref(bs); + + /* this destroys throttle_node */ + blk_remove_bs(blk); + + blk_insert_bs(blk, bs, &error_abort); + bdrv_unref(bs); } =20 /* should be called before blk_set_io_limits if a limit is set */ -void blk_io_limits_enable(BlockBackend *blk, const char *group) +void blk_io_limits_enable(BlockBackend *blk, const char *group, Error **e= rrp) { - assert(!blk->public.throttle_group_member.throttle_state); - throttle_group_register_tgm(&blk->public.throttle_group_member, - group, blk_get_aio_context(blk)); + BlockDriverState *bs =3D blk_bs(blk), *throttle_node; + QDict *options =3D qdict_new(); + Error *local_err =3D NULL; + + bdrv_drained_begin(bs); + /* + * increase bs ref count so it doesn't get deleted when removed + * from the BlockBackend's root + * */ + bdrv_ref(bs); + blk_remove_bs(blk); + + qdict_set_default_str(options, "file", bs->node_name); + qdict_set_default_str(options, QEMU_OPT_THROTTLE_GROUP_NAME, group); + throttle_node =3D bdrv_new_open_driver(bdrv_find_format("throttle"), + NULL, bdrv_get_flags(bs), options, errp); + QDECREF(options); + if (!throttle_node) { + blk_insert_bs(blk, bs, &error_abort); + bdrv_unref(bs); + bdrv_drained_end(bs); + return; + } + throttle_node->implicit =3D true; + /* bs will be throttle_node's child now so unref it*/ + bdrv_unref(bs); + + blk_insert_bs(blk, throttle_node, &local_err); + if (local_err) { + bdrv_ref(bs); + bdrv_unref(throttle_node); + blk_insert_bs(blk, bs, &error_abort); + bdrv_unref(bs); + error_propagate(errp, local_err); + return; + } + bdrv_unref(throttle_node); + + assert(throttle_node->file->bs =3D=3D bs); + assert(throttle_node->refcnt =3D=3D 1); + + bdrv_drained_end(bs); + + blk_get_public(blk)->throttle_node =3D throttle_node; } =20 -void blk_io_limits_update_group(BlockBackend *blk, const char *group) +void blk_io_limits_update_group(BlockBackend *blk, const char *group, Erro= r **errp) { + ThrottleGroupMember *tgm; + Error *local_err =3D NULL; + /* this BB is not part of any group */ - if (!blk->public.throttle_group_member.throttle_state) { + if (!blk->public.throttle_node) { return; } =20 + tgm =3D throttle_get_tgm(blk->public.throttle_node); /* this BB is a part of the same group than the one we want */ - if (!g_strcmp0(throttle_group_get_name(&blk->public.throttle_group_mem= ber), + if (!g_strcmp0(throttle_group_get_name(tgm), group)) { return; } =20 - /* need to change the group this bs belong to */ - blk_io_limits_disable(blk); - blk_io_limits_enable(blk, group); + /* need to change the group this bs belongs to */ + blk_io_limits_disable(blk, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + blk_io_limits_enable(blk, group, errp); } =20 static void blk_root_drained_begin(BdrvChild *child) { + ThrottleGroupMember *tgm; BlockBackend *blk =3D child->opaque; =20 if (++blk->quiesce_counter =3D=3D 1) { @@ -1958,19 +1993,25 @@ static void blk_root_drained_begin(BdrvChild *child) =20 /* Note that blk->root may not be accessible here yet if we are just * attaching to a BlockDriverState that is drained. Use child instead.= */ - - if (atomic_fetch_inc(&blk->public.throttle_group_member.io_limits_disa= bled) =3D=3D 0) { - throttle_group_restart_tgm(&blk->public.throttle_group_member); + if (blk->public.throttle_node) { + tgm =3D throttle_get_tgm(blk->public.throttle_node); + if (atomic_fetch_inc(&tgm->io_limits_disabled) =3D=3D 0) { + throttle_group_restart_tgm(tgm); + } } } =20 static void blk_root_drained_end(BdrvChild *child) { + ThrottleGroupMember *tgm; BlockBackend *blk =3D child->opaque; assert(blk->quiesce_counter); =20 - assert(blk->public.throttle_group_member.io_limits_disabled); - atomic_dec(&blk->public.throttle_group_member.io_limits_disabled); + if (blk->public.throttle_node) { + tgm =3D throttle_get_tgm(blk->public.throttle_node); + assert(tgm->io_limits_disabled); + atomic_dec(&tgm->io_limits_disabled); + } =20 if (--blk->quiesce_counter =3D=3D 0) { if (blk->dev_ops && blk->dev_ops->drained_end) { diff --git a/block/qapi.c b/block/qapi.c index 8d18920ae1..cfc3236757 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -66,11 +66,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *b= lk, =20 info->detect_zeroes =3D bs->detect_zeroes; =20 - if (blk && blk_get_public(blk)->throttle_group_member.throttle_state) { + if (blk && blk_get_public(blk)->throttle_node) { ThrottleConfig cfg; - BlockBackendPublic *blkp =3D blk_get_public(blk); + ThrottleGroupMember *tgm =3D throttle_get_tgm(blk_get_public(blk)-= >throttle_node); =20 - throttle_group_get_config(&blkp->throttle_group_member, &cfg); + throttle_group_get_config(tgm, &cfg); =20 info->bps =3D cfg.buckets[THROTTLE_BPS_TOTAL].avg; info->bps_rd =3D cfg.buckets[THROTTLE_BPS_READ].avg; @@ -119,7 +119,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *b= lk, =20 info->has_group =3D true; info->group =3D - g_strdup(throttle_group_get_name(&blkp->throttle_group_member)= ); + g_strdup(throttle_group_get_name(tgm)); } =20 info->write_threshold =3D bdrv_write_threshold_get(bs); @@ -148,7 +148,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *b= lk, /* Skip automatically inserted nodes that the user isn't aware of = for * query-block (blk !=3D NULL), but not for query-named-block-node= s */ while (blk && bs0 && bs0->drv && bs0->implicit) { - bs0 =3D backing_bs(bs0); + bs0 =3D child_bs(bs0); } } =20 @@ -336,7 +336,7 @@ static void bdrv_query_info(BlockBackend *blk, BlockInf= o **p_info, =20 /* Skip automatically inserted nodes that the user isn't aware of */ while (bs && bs->drv && bs->implicit) { - bs =3D backing_bs(bs); + bs =3D child_bs(bs); } =20 info->device =3D g_strdup(blk_name(blk)); @@ -465,7 +465,7 @@ static BlockStats *bdrv_query_bds_stats(BlockDriverStat= e *bs, * a BlockBackend-level command. Stay at the exact node for a node-lev= el * command. */ while (blk_level && bs->drv && bs->implicit) { - bs =3D backing_bs(bs); + bs =3D child_bs(bs); assert(bs); } =20 diff --git a/block/throttle.c b/block/throttle.c index f3395462fb..f7d1510c79 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -38,6 +38,14 @@ static QemuOptsList throttle_opts =3D { }, }; =20 +static BlockDriver bdrv_throttle; + +ThrottleGroupMember *throttle_get_tgm(BlockDriverState *bs) +{ + assert(bs->drv =3D=3D &bdrv_throttle); + return (ThrottleGroupMember *)bs->opaque; +} + /* Extract ThrottleConfig options. Assumes cfg is initialized and will be * checked for validity. */ diff --git a/blockdev.c b/blockdev.c index d903a23786..6fafd0efbc 100644 --- a/blockdev.c +++ b/blockdev.c @@ -607,7 +607,14 @@ static BlockBackend *blockdev_init(const char *file, Q= Dict *bs_opts, if (!throttling_group) { throttling_group =3D id; } - blk_io_limits_enable(blk, throttling_group); + blk_io_limits_enable(blk, throttling_group, &error); + if (error) { + error_propagate(errp, error); + blk_unref(blk); + blk =3D NULL; + goto err_no_bs_opts; + + } blk_set_io_limits(blk, &cfg); } =20 @@ -2616,6 +2623,9 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, = Error **errp) BlockDriverState *bs; BlockBackend *blk; AioContext *aio_context; + BlockDriverState *throttle_node =3D NULL; + ThrottleGroupMember *tgm; + Error *local_err =3D NULL; =20 blk =3D qmp_get_blk(arg->has_device ? arg->device : NULL, arg->has_id ? arg->id : NULL, @@ -2691,19 +2701,38 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg= , Error **errp) if (throttle_enabled(&cfg)) { /* Enable I/O limits if they're not enabled yet, otherwise * just update the throttling group. */ - if (!blk_get_public(blk)->throttle_group_member.throttle_state) { - blk_io_limits_enable(blk, - arg->has_group ? arg->group : - arg->has_device ? arg->device : - arg->id); - } else if (arg->has_group) { - blk_io_limits_update_group(blk, arg->group); + if (!blk_get_public(blk)->throttle_node) { + blk_io_limits_enable(blk, arg->has_group ? arg->group : + arg->has_device ? arg->device : arg->id, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto out; + } } - /* Set the new throttling configuration */ - blk_set_io_limits(blk, &cfg); - } else if (blk_get_public(blk)->throttle_group_member.throttle_state) { - /* If all throttling settings are set to 0, disable I/O limits */ - blk_io_limits_disable(blk); + + if (arg->has_group) { + /* move throttle node membership to arg->group */ + blk_io_limits_update_group(blk, arg->group, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto out; + } + } + + throttle_node =3D blk_get_public(blk)->throttle_node; + tgm =3D throttle_get_tgm(throttle_node); + throttle_group_config(tgm, &cfg); + } else if (blk_get_public(blk)->throttle_node) { + /* + * If all throttling settings are set to 0, disable I/O limits + * by deleting the legacy throttle node + * */ + blk_io_limits_disable(blk, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto out; + } + } =20 out: diff --git a/include/block/block_int.h b/include/block/block_int.h index 9eeae490f0..e19bd81498 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -514,6 +514,7 @@ extern const BdrvChildRole child_backing; =20 struct BdrvChild { BlockDriverState *bs; + BlockDriverState *parent_bs; char *name; const BdrvChildRole *role; void *opaque; @@ -695,11 +696,23 @@ typedef enum BlockMirrorBackingMode { MIRROR_LEAVE_BACKING_CHAIN, } BlockMirrorBackingMode; =20 +static inline BlockDriverState *file_bs(BlockDriverState *bs) +{ + return bs->file ? bs->file->bs : NULL; +} static inline BlockDriverState *backing_bs(BlockDriverState *bs) { return bs->backing ? bs->backing->bs : NULL; } =20 +/* Returns either bs->file->bs or bs->backing->bs. Used for filter drivers, + * which only have one child */ +static inline BlockDriverState *child_bs(BlockDriverState *bs) +{ + assert(!(file_bs(bs) && backing_bs(bs))); + return backing_bs(bs) ? backing_bs(bs) : file_bs(bs); +} + =20 /* Essential block drivers which must always be statically linked into qem= u, and * which therefore can be accessed without using bdrv_find_format() */ diff --git a/include/block/throttle-groups.h b/include/block/throttle-group= s.h index 82f030523f..ba86a9601a 100644 --- a/include/block/throttle-groups.h +++ b/include/block/throttle-groups.h @@ -76,5 +76,7 @@ void coroutine_fn throttle_group_co_io_limits_intercept(T= hrottleGroupMember *tgm void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, AioContext *new_context); void throttle_group_detach_aio_context(ThrottleGroupMember *tgm); +ThrottleGroupMember *throttle_get_tgm(BlockDriverState *bs); + =20 #endif diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 0e0cda7521..2079657d3a 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -73,7 +73,7 @@ typedef struct BlockDevOps { * friends so that BlockBackends can be kept in lists outside block-backen= d.c * */ typedef struct BlockBackendPublic { - ThrottleGroupMember throttle_group_member; + BlockDriverState *throttle_node; } BlockBackendPublic; =20 BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm); @@ -224,8 +224,8 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, void *opaque, int ret); =20 void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg); -void blk_io_limits_disable(BlockBackend *blk); -void blk_io_limits_enable(BlockBackend *blk, const char *group); -void blk_io_limits_update_group(BlockBackend *blk, const char *group); +void blk_io_limits_disable(BlockBackend *blk, Error **errp); +void blk_io_limits_enable(BlockBackend *blk, const char *group, Error **er= rp); +void blk_io_limits_update_group(BlockBackend *blk, const char *group, Erro= r **errp); =20 #endif diff --git a/tests/test-throttle.c b/tests/test-throttle.c index 0ea9093eee..e1403a2039 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -594,7 +594,6 @@ static void test_groups(void) { ThrottleConfig cfg1, cfg2; BlockBackend *blk1, *blk2, *blk3; - BlockBackendPublic *blkp1, *blkp2, *blkp3; ThrottleGroupMember *tgm1, *tgm2, *tgm3; =20 /* No actual I/O is performed on these devices */ @@ -602,13 +601,9 @@ static void test_groups(void) blk2 =3D blk_new(0, BLK_PERM_ALL); blk3 =3D blk_new(0, BLK_PERM_ALL); =20 - blkp1 =3D blk_get_public(blk1); - blkp2 =3D blk_get_public(blk2); - blkp3 =3D blk_get_public(blk3); - - tgm1 =3D &blkp1->throttle_group_member; - tgm2 =3D &blkp2->throttle_group_member; - tgm3 =3D &blkp3->throttle_group_member; + tgm1 =3D g_new0(ThrottleGroupMember, 1); + tgm2 =3D g_new0(ThrottleGroupMember, 1); + tgm3 =3D g_new0(ThrottleGroupMember, 1); =20 g_assert(tgm1->throttle_state =3D=3D NULL); g_assert(tgm2->throttle_state =3D=3D NULL); @@ -655,6 +650,10 @@ static void test_groups(void) g_assert(tgm1->throttle_state =3D=3D NULL); g_assert(tgm2->throttle_state =3D=3D NULL); g_assert(tgm3->throttle_state =3D=3D NULL); + + g_free(tgm1); + g_free(tgm2); + g_free(tgm3); } =20 int main(int argc, char **argv) --=20 2.11.0