From nobody Mon Apr 29 13:17:53 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 1504707042041347.1280826392847; Wed, 6 Sep 2017 07:10:42 -0700 (PDT) Received: from localhost ([::1]:36306 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb2O-0002ij-Mq for importer@patchew.org; Wed, 06 Sep 2017 10:10:40 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50114) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavD-0005Yg-2V for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpav7-0000tV-8O for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:15 -0400 Received: from mx1.redhat.com ([209.132.183.28]:34204) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpauq-0000iH-O2; Wed, 06 Sep 2017 10:02:52 -0400 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 B9169356E8; Wed, 6 Sep 2017 14:02:51 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id E680118C61; Wed, 6 Sep 2017 14:02:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com B9169356E8 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:33 +0200 Message-Id: <20170906140246.7326-2-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:02:51 +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] [PULL 01/14] block: pass bdrv_* methods to bs->file by default in block filters 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, 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" From: Manos Pitsidianakis The following functions fail if bs->drv is a filter and does not implement them: bdrv_probe_blocksizes bdrv_probe_geometry bdrv_truncate bdrv_has_zero_init bdrv_get_info Instead, the call should be passed to bs->file if it exists, to allow filter drivers to support those methods without implementing them. This commit makes `drv->is_filter =3D true` imply that these callbacks will be forwarded to bs->file by default, so disabling support for these functions must be done explicitly. Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Manos Pitsidianakis Signed-off-by: Kevin Wolf --- include/block/block_int.h | 6 +++++- block.c | 21 +++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/include/block/block_int.h b/include/block/block_int.h index 7571c0aaaf..71183cc76e 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -87,7 +87,11 @@ struct BlockDriver { const char *format_name; int instance_size; =20 - /* set to true if the BlockDriver is a block filter */ + /* set to true if the BlockDriver is a block filter. Block filters pass + * certain callbacks that refer to data (see block.c) to their bs->fil= e if + * the driver doesn't implement them. Drivers that do not wish to forw= ard + * must implement them and return -ENOTSUP. + */ bool is_filter; /* for snapshots block filter like Quorum can implement the * following recursive callback. diff --git a/block.c b/block.c index b749bd6404..175e8d35ff 100644 --- a/block.c +++ b/block.c @@ -496,6 +496,8 @@ int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSi= zes *bsz) =20 if (drv && drv->bdrv_probe_blocksizes) { return drv->bdrv_probe_blocksizes(bs, bsz); + } else if (drv && drv->is_filter && bs->file) { + return bdrv_probe_blocksizes(bs->file->bs, bsz); } =20 return -ENOTSUP; @@ -513,6 +515,8 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometr= y *geo) =20 if (drv && drv->bdrv_probe_geometry) { return drv->bdrv_probe_geometry(bs, geo); + } else if (drv && drv->is_filter && bs->file) { + return bdrv_probe_geometry(bs->file->bs, geo); } =20 return -ENOTSUP; @@ -3426,11 +3430,15 @@ int bdrv_truncate(BdrvChild *child, int64_t offset,= PreallocMode prealloc, =20 assert(child->perm & BLK_PERM_RESIZE); =20 + /* if bs->drv =3D=3D NULL, bs is closed, so there's nothing to do here= */ if (!drv) { error_setg(errp, "No medium inserted"); return -ENOMEDIUM; } if (!drv->bdrv_truncate) { + if (bs->file && drv->is_filter) { + return bdrv_truncate(bs->file, offset, prealloc, errp); + } error_setg(errp, "Image format driver does not support resize"); return -ENOTSUP; } @@ -3767,6 +3775,9 @@ int bdrv_has_zero_init(BlockDriverState *bs) if (bs->drv->bdrv_has_zero_init) { return bs->drv->bdrv_has_zero_init(bs); } + if (bs->file && bs->drv->is_filter) { + return bdrv_has_zero_init(bs->file->bs); + } =20 /* safe default */ return 0; @@ -3821,10 +3832,16 @@ void bdrv_get_backing_filename(BlockDriverState *bs, int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BlockDriver *drv =3D bs->drv; - if (!drv) + /* if bs->drv =3D=3D NULL, bs is closed, so there's nothing to do here= */ + if (!drv) { return -ENOMEDIUM; - if (!drv->bdrv_get_info) + } + if (!drv->bdrv_get_info) { + if (bs->file && drv->is_filter) { + return bdrv_get_info(bs->file->bs, bdi); + } return -ENOTSUP; + } memset(bdi, 0, sizeof(*bdi)); return drv->bdrv_get_info(bs, bdi); } --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504706727044784.8118581622086; Wed, 6 Sep 2017 07:05:27 -0700 (PDT) Received: from localhost ([::1]:36279 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpaxJ-0006uj-Ur for importer@patchew.org; Wed, 06 Sep 2017 10:05:26 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50097) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavB-0005Wu-ES for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpav1-0000po-SO for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:13 -0400 Received: from mx1.redhat.com ([209.132.183.28]:38520) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpaur-0000il-Ne; Wed, 06 Sep 2017 10:02:53 -0400 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 C091FC04B92C; Wed, 6 Sep 2017 14:02:52 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 05F1618C47; Wed, 6 Sep 2017 14:02:51 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com C091FC04B92C Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:34 +0200 Message-Id: <20170906140246.7326-3-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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.31]); Wed, 06 Sep 2017 14:02:52 +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] [PULL 02/14] block: remove unused bdrv_media_changed 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, 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" From: Manos Pitsidianakis This function is not used anywhere, so remove it. Markus Armbruster adds: The i82078 floppy device model used to call bdrv_media_changed() to implement its media change bit when backed by a host floppy. This went away in 21fcf36 "fdc: simplify media change handling". Probably broke host floppy media change. Host floppy pass-through was dropped in commit f709623. bdrv_media_changed() has never been used for anything else. Remove it. (Source is Message-ID: <87y3ruaypm.fsf@dusky.pond.sub.org>) Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Manos Pitsidianakis Signed-off-by: Kevin Wolf --- include/block/block.h | 1 - include/block/block_int.h | 1 - block.c | 14 -------------- block/raw-format.c | 6 ------ 4 files changed, 22 deletions(-) diff --git a/include/block/block.h b/include/block/block.h index ab80195378..2ad18775af 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -441,7 +441,6 @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool r= ead_only, int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); bool bdrv_is_sg(BlockDriverState *bs); bool bdrv_is_inserted(BlockDriverState *bs); -int bdrv_media_changed(BlockDriverState *bs); void bdrv_lock_medium(BlockDriverState *bs, bool locked); void bdrv_eject(BlockDriverState *bs, bool eject_flag); const char *bdrv_get_format_name(BlockDriverState *bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index 71183cc76e..ca4e7e5629 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -248,7 +248,6 @@ struct BlockDriver { =20 /* removable device specific */ bool (*bdrv_is_inserted)(BlockDriverState *bs); - int (*bdrv_media_changed)(BlockDriverState *bs); void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); =20 diff --git a/block.c b/block.c index 175e8d35ff..6dd47e414e 100644 --- a/block.c +++ b/block.c @@ -4192,20 +4192,6 @@ bool bdrv_is_inserted(BlockDriverState *bs) } =20 /** - * Return whether the media changed since the last call to this - * function, or -ENOTSUP if we don't know. Most drivers don't know. - */ -int bdrv_media_changed(BlockDriverState *bs) -{ - BlockDriver *drv =3D bs->drv; - - if (drv && drv->bdrv_media_changed) { - return drv->bdrv_media_changed(bs); - } - return -ENOTSUP; -} - -/** * If eject_flag is TRUE, eject the media. Otherwise, close the tray */ void bdrv_eject(BlockDriverState *bs, bool eject_flag) diff --git a/block/raw-format.c b/block/raw-format.c index 142649ed56..ab552c0954 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -372,11 +372,6 @@ static int raw_truncate(BlockDriverState *bs, int64_t = offset, return bdrv_truncate(bs->file, offset, prealloc, errp); } =20 -static int raw_media_changed(BlockDriverState *bs) -{ - return bdrv_media_changed(bs->file->bs); -} - static void raw_eject(BlockDriverState *bs, bool eject_flag) { bdrv_eject(bs->file->bs, eject_flag); @@ -510,7 +505,6 @@ BlockDriver bdrv_raw =3D { .bdrv_refresh_limits =3D &raw_refresh_limits, .bdrv_probe_blocksizes =3D &raw_probe_blocksizes, .bdrv_probe_geometry =3D &raw_probe_geometry, - .bdrv_media_changed =3D &raw_media_changed, .bdrv_eject =3D &raw_eject, .bdrv_lock_medium =3D &raw_lock_medium, .bdrv_co_ioctl =3D &raw_co_ioctl, --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 150470671929463.94520824960625; Wed, 6 Sep 2017 07:05:19 -0700 (PDT) Received: from localhost ([::1]:36278 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpaxC-0006o3-6T for importer@patchew.org; Wed, 06 Sep 2017 10:05:18 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50062) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpav8-0005TV-2F for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpav2-0000qH-GI for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:10 -0400 Received: from mx1.redhat.com ([209.132.183.28]:50796) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpaus-0000jp-Vw; Wed, 06 Sep 2017 10:02:55 -0400 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 0CE026DB; Wed, 6 Sep 2017 14:02:54 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0D07518C4F; Wed, 6 Sep 2017 14:02:52 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 0CE026DB Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:35 +0200 Message-Id: <20170906140246.7326-4-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:02:54 +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] [PULL 03/14] block: remove bdrv_truncate callback in blkdebug 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, 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" From: Manos Pitsidianakis Now that bdrv_truncate is passed to bs->file by default, remove the callback from block/blkdebug.c and set is_filter to true. is_filter also gi= ves access to other callbacks that are forwarded automatically to bs->file for filters. Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Manos Pitsidianakis Signed-off-by: Kevin Wolf --- block/blkdebug.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index 8e385acf54..f10e3e5638 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -808,12 +808,6 @@ static int64_t blkdebug_getlength(BlockDriverState *bs) return bdrv_getlength(bs->file->bs); } =20 -static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) -{ - return bdrv_truncate(bs->file, offset, prealloc, errp); -} - static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) { BDRVBlkdebugState *s =3D bs->opaque; @@ -896,6 +890,7 @@ static BlockDriver bdrv_blkdebug =3D { .format_name =3D "blkdebug", .protocol_name =3D "blkdebug", .instance_size =3D sizeof(BDRVBlkdebugState), + .is_filter =3D true, =20 .bdrv_parse_filename =3D blkdebug_parse_filename, .bdrv_file_open =3D blkdebug_open, @@ -904,7 +899,6 @@ static BlockDriver bdrv_blkdebug =3D { .bdrv_child_perm =3D bdrv_filter_default_perms, =20 .bdrv_getlength =3D blkdebug_getlength, - .bdrv_truncate =3D blkdebug_truncate, .bdrv_refresh_filename =3D blkdebug_refresh_filename, .bdrv_refresh_limits =3D blkdebug_refresh_limits, =20 --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504706952511738.3789275205082; Wed, 6 Sep 2017 07:09:12 -0700 (PDT) Received: from localhost ([::1]:36294 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb0w-0001gR-1H for importer@patchew.org; Wed, 06 Sep 2017 10:09:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50198) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavJ-0005fQ-QR for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpav9-0000v9-Or for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:21 -0400 Received: from mx1.redhat.com ([209.132.183.28]:45584) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpauu-0000kf-08; Wed, 06 Sep 2017 10:02:56 -0400 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 11C75C0587DE; Wed, 6 Sep 2017 14:02:55 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4E08A18C4F; Wed, 6 Sep 2017 14:02:54 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 11C75C0587DE Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:36 +0200 Message-Id: <20170906140246.7326-5-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:02:55 +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] [PULL 04/14] block: add default implementations for bdrv_co_get_block_status() 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, 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" From: Manos Pitsidianakis bdrv_co_get_block_status_from_file() and bdrv_co_get_block_status_from_backing() set *file to bs->file and bs->backing respectively, so that bdrv_co_get_block_status() can recurse to them. Future block drivers won't have to duplicate code to implement this. Reviewed-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Signed-off-by: Manos Pitsidianakis Signed-off-by: Kevin Wolf --- include/block/block_int.h | 18 ++++++++++++++++++ block/blkdebug.c | 12 +----------- block/commit.c | 12 +----------- block/io.c | 26 ++++++++++++++++++++++++++ block/mirror.c | 12 +----------- 5 files changed, 47 insertions(+), 33 deletions(-) diff --git a/include/block/block_int.h b/include/block/block_int.h index ca4e7e5629..223801e4fb 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -964,6 +964,24 @@ void bdrv_format_default_perms(BlockDriverState *bs, B= drvChild *c, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared); =20 +/* + * Default implementation for drivers to pass bdrv_co_get_block_status() to + * their file. + */ +int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *= bs, + int64_t sector_num, + int nb_sectors, + int *pnum, + BlockDriverState *= *file); +/* + * Default implementation for drivers to pass bdrv_co_get_block_status() to + * their backing file. + */ +int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverStat= e *bs, + int64_t sector_= num, + int nb_sectors, + int *pnum, + BlockDriverStat= e **file); const char *bdrv_get_parent_name(const BlockDriverState *bs); void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp); bool blk_dev_has_removable_media(BlockBackend *blk); diff --git a/block/blkdebug.c b/block/blkdebug.c index f10e3e5638..46e53f2f09 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -628,16 +628,6 @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriv= erState *bs, return bdrv_co_pdiscard(bs->file->bs, offset, bytes); } =20 -static int64_t coroutine_fn blkdebug_co_get_block_status( - BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum, - BlockDriverState **file) -{ - *pnum =3D nb_sectors; - *file =3D bs->file->bs; - return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | - (sector_num << BDRV_SECTOR_BITS); -} - static void blkdebug_close(BlockDriverState *bs) { BDRVBlkdebugState *s =3D bs->opaque; @@ -907,7 +897,7 @@ static BlockDriver bdrv_blkdebug =3D { .bdrv_co_flush_to_disk =3D blkdebug_co_flush, .bdrv_co_pwrite_zeroes =3D blkdebug_co_pwrite_zeroes, .bdrv_co_pdiscard =3D blkdebug_co_pdiscard, - .bdrv_co_get_block_status =3D blkdebug_co_get_block_status, + .bdrv_co_get_block_status =3D bdrv_co_get_block_status_from_file, =20 .bdrv_debug_event =3D blkdebug_debug_event, .bdrv_debug_breakpoint =3D blkdebug_debug_breakpoint, diff --git a/block/commit.c b/block/commit.c index c7857c3321..898d91f653 100644 --- a/block/commit.c +++ b/block/commit.c @@ -244,16 +244,6 @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDr= iverState *bs, return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); } =20 -static int64_t coroutine_fn bdrv_commit_top_get_block_status( - BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum, - BlockDriverState **file) -{ - *pnum =3D nb_sectors; - *file =3D bs->backing->bs; - return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | - (sector_num << BDRV_SECTOR_BITS); -} - static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *= opts) { bdrv_refresh_filename(bs->backing->bs); @@ -279,7 +269,7 @@ static void bdrv_commit_top_child_perm(BlockDriverState= *bs, BdrvChild *c, static BlockDriver bdrv_commit_top =3D { .format_name =3D "commit_top", .bdrv_co_preadv =3D bdrv_commit_top_preadv, - .bdrv_co_get_block_status =3D bdrv_commit_top_get_block_status, + .bdrv_co_get_block_status =3D bdrv_co_get_block_status_from_backing, .bdrv_refresh_filename =3D bdrv_commit_top_refresh_filename, .bdrv_close =3D bdrv_commit_top_close, .bdrv_child_perm =3D bdrv_commit_top_child_perm, diff --git a/block/io.c b/block/io.c index 26003814eb..4378ae4c7d 100644 --- a/block/io.c +++ b/block/io.c @@ -1714,6 +1714,32 @@ typedef struct BdrvCoGetBlockStatusData { bool done; } BdrvCoGetBlockStatusData; =20 +int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *= bs, + int64_t sector_num, + int nb_sectors, + int *pnum, + BlockDriverState *= *file) +{ + assert(bs->file && bs->file->bs); + *pnum =3D nb_sectors; + *file =3D bs->file->bs; + return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | + (sector_num << BDRV_SECTOR_BITS); +} + +int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverStat= e *bs, + int64_t sector_= num, + int nb_sectors, + int *pnum, + BlockDriverStat= e **file) +{ + assert(bs->backing && bs->backing->bs); + *pnum =3D nb_sectors; + *file =3D bs->backing->bs; + return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | + (sector_num << BDRV_SECTOR_BITS); +} + /* * Returns the allocation status of the specified sectors. * Drivers not implementing the functionality are assumed to not support diff --git a/block/mirror.c b/block/mirror.c index 429751b9fe..6531652d73 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1059,16 +1059,6 @@ static int coroutine_fn bdrv_mirror_top_flush(BlockD= riverState *bs) return bdrv_co_flush(bs->backing->bs); } =20 -static int64_t coroutine_fn bdrv_mirror_top_get_block_status( - BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum, - BlockDriverState **file) -{ - *pnum =3D nb_sectors; - *file =3D bs->backing->bs; - return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | - (sector_num << BDRV_SECTOR_BITS); -} - static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes, BdrvRequestFlags flags) { @@ -1115,7 +1105,7 @@ static BlockDriver bdrv_mirror_top =3D { .bdrv_co_pwrite_zeroes =3D bdrv_mirror_top_pwrite_zeroes, .bdrv_co_pdiscard =3D bdrv_mirror_top_pdiscard, .bdrv_co_flush =3D bdrv_mirror_top_flush, - .bdrv_co_get_block_status =3D bdrv_mirror_top_get_block_status, + .bdrv_co_get_block_status =3D bdrv_co_get_block_status_from_backing, .bdrv_refresh_filename =3D bdrv_mirror_top_refresh_filename, .bdrv_close =3D bdrv_mirror_top_close, .bdrv_child_perm =3D bdrv_mirror_top_child_perm, --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504706890694829.9467405544169; Wed, 6 Sep 2017 07:08:10 -0700 (PDT) Received: from localhost ([::1]:36290 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpazx-0000rE-Ko for importer@patchew.org; Wed, 06 Sep 2017 10:08:09 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50083) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavA-0005W1-Dm for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpav4-0000rh-B0 for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:12 -0400 Received: from mx1.redhat.com ([209.132.183.28]:38698) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpauv-0000lR-9k; Wed, 06 Sep 2017 10:02:57 -0400 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 4406AC04B924; Wed, 6 Sep 2017 14:02:56 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 527C717A60; Wed, 6 Sep 2017 14:02:55 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 4406AC04B924 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:37 +0200 Message-Id: <20170906140246.7326-6-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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.31]); Wed, 06 Sep 2017 14:02:56 +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] [PULL 05/14] qcow: Change signature of get_cluster_offset() 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, 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" From: Eric Blake The old signature has an ambiguous meaning for a return of 0: either no allocation was requested or necessary, or an error occurred (but any errno associated with the error is lost to the caller, which then has to assume EIO). Better is to follow the example of qcow2, by changing the signature to have a separate return value that cleanly distinguishes between failure and success, along with a parameter that cleanly holds a 64-bit value. Then update all callers. While auditing that all return paths return a negative errno (rather than -1), I also simplified places where we can pass NULL rather than a local Error that just gets thrown away. Suggested-by: Kevin Wolf Signed-off-by: Eric Blake Signed-off-by: Kevin Wolf --- block/qcow.c | 123 +++++++++++++++++++++++++++++++++++--------------------= ---- 1 file changed, 73 insertions(+), 50 deletions(-) diff --git a/block/qcow.c b/block/qcow.c index 63904a26ee..d07bef6306 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -347,19 +347,21 @@ static int qcow_reopen_prepare(BDRVReopenState *state, * 'compressed_size'. 'compressed_size' must be > 0 and < * cluster_size * - * return 0 if not allocated. + * return 0 if not allocated, 1 if *result is assigned, and negative + * errno on failure. */ -static uint64_t get_cluster_offset(BlockDriverState *bs, - uint64_t offset, int allocate, - int compressed_size, - int n_start, int n_end) +static int get_cluster_offset(BlockDriverState *bs, + uint64_t offset, int allocate, + int compressed_size, + int n_start, int n_end, uint64_t *result) { BDRVQcowState *s =3D bs->opaque; - int min_index, i, j, l1_index, l2_index; + int min_index, i, j, l1_index, l2_index, ret; uint64_t l2_offset, *l2_table, cluster_offset, tmp; uint32_t min_count; int new_l2_table; =20 + *result =3D 0; l1_index =3D offset >> (s->l2_bits + s->cluster_bits); l2_offset =3D s->l1_table[l1_index]; new_l2_table =3D 0; @@ -373,10 +375,12 @@ static uint64_t get_cluster_offset(BlockDriverState *= bs, /* update the L1 entry */ s->l1_table[l1_index] =3D l2_offset; tmp =3D cpu_to_be64(l2_offset); - if (bdrv_pwrite_sync(bs->file, - s->l1_table_offset + l1_index * sizeof(tmp), - &tmp, sizeof(tmp)) < 0) - return 0; + ret =3D bdrv_pwrite_sync(bs->file, + s->l1_table_offset + l1_index * sizeof(tmp), + &tmp, sizeof(tmp)); + if (ret < 0) { + return ret; + } new_l2_table =3D 1; } for(i =3D 0; i < L2_CACHE_SIZE; i++) { @@ -403,14 +407,17 @@ static uint64_t get_cluster_offset(BlockDriverState *= bs, l2_table =3D s->l2_cache + (min_index << s->l2_bits); if (new_l2_table) { memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); - if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table, - s->l2_size * sizeof(uint64_t)) < 0) - return 0; + ret =3D bdrv_pwrite_sync(bs->file, l2_offset, l2_table, + s->l2_size * sizeof(uint64_t)); + if (ret < 0) { + return ret; + } } else { - if (bdrv_pread(bs->file, l2_offset, l2_table, - s->l2_size * sizeof(uint64_t)) !=3D - s->l2_size * sizeof(uint64_t)) - return 0; + ret =3D bdrv_pread(bs->file, l2_offset, l2_table, + s->l2_size * sizeof(uint64_t)); + if (ret < 0) { + return ret; + } } s->l2_cache_offsets[min_index] =3D l2_offset; s->l2_cache_counts[min_index] =3D 1; @@ -427,16 +434,18 @@ static uint64_t get_cluster_offset(BlockDriverState *= bs, /* if the cluster is already compressed, we must decompress it in the case it is not completely overwritten */ - if (decompress_cluster(bs, cluster_offset) < 0) - return 0; + if (decompress_cluster(bs, cluster_offset) < 0) { + return -EIO; + } cluster_offset =3D bdrv_getlength(bs->file->bs); cluster_offset =3D (cluster_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); /* write the cluster content */ - if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, - s->cluster_size) !=3D - s->cluster_size) - return -1; + ret =3D bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, + s->cluster_size); + if (ret < 0) { + return ret; + } } else { cluster_offset =3D bdrv_getlength(bs->file->bs); if (allocate =3D=3D 1) { @@ -459,13 +468,14 @@ static uint64_t get_cluster_offset(BlockDriverState *= bs, s->cluster_data, BDRV_SECTOR_SIZE, NULL) < 0) { - errno =3D EIO; - return -1; + return -EIO; + } + ret =3D bdrv_pwrite(bs->file, + cluster_offset + i * 512, + s->cluster_data, 512); + if (ret < 0) { + return ret; } - if (bdrv_pwrite(bs->file, - cluster_offset + i * 512, - s->cluster_data, 512) !=3D 512) - return -1; } } } @@ -477,23 +487,29 @@ static uint64_t get_cluster_offset(BlockDriverState *= bs, /* update L2 table */ tmp =3D cpu_to_be64(cluster_offset); l2_table[l2_index] =3D tmp; - if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp), - &tmp, sizeof(tmp)) < 0) - return 0; + ret =3D bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(t= mp), + &tmp, sizeof(tmp)); + if (ret < 0) { + return ret; + } } - return cluster_offset; + *result =3D cluster_offset; + return 1; } =20 static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **= file) { BDRVQcowState *s =3D bs->opaque; - int index_in_cluster, n; + int index_in_cluster, n, ret; uint64_t cluster_offset; =20 qemu_co_mutex_lock(&s->lock); - cluster_offset =3D get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); + ret =3D get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0, &cluster_o= ffset); qemu_co_mutex_unlock(&s->lock); + if (ret < 0) { + return ret; + } index_in_cluster =3D sector_num & (s->cluster_sectors - 1); n =3D s->cluster_sectors - index_in_cluster; if (n > nb_sectors) @@ -585,8 +601,11 @@ static coroutine_fn int qcow_co_readv(BlockDriverState= *bs, int64_t sector_num, =20 while (nb_sectors !=3D 0) { /* prepare next request */ - cluster_offset =3D get_cluster_offset(bs, sector_num << 9, - 0, 0, 0, 0); + ret =3D get_cluster_offset(bs, sector_num << 9, + 0, 0, 0, 0, &cluster_offset); + if (ret < 0) { + break; + } index_in_cluster =3D sector_num & (s->cluster_sectors - 1); n =3D s->cluster_sectors - index_in_cluster; if (n > nb_sectors) { @@ -603,7 +622,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState = *bs, int64_t sector_num, ret =3D bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov= ); qemu_co_mutex_lock(&s->lock); if (ret < 0) { - goto fail; + break; } } else { /* Note: in this case, no need to wait */ @@ -612,13 +631,15 @@ static coroutine_fn int qcow_co_readv(BlockDriverStat= e *bs, int64_t sector_num, } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ if (decompress_cluster(bs, cluster_offset) < 0) { - goto fail; + ret =3D -EIO; + break; } memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); } else { if ((cluster_offset & 511) !=3D 0) { - goto fail; + ret =3D -EIO; + break; } hd_iov.iov_base =3D (void *)buf; hd_iov.iov_len =3D n * 512; @@ -635,7 +656,8 @@ static coroutine_fn int qcow_co_readv(BlockDriverState = *bs, int64_t sector_num, assert(s->crypto); if (qcrypto_block_decrypt(s->crypto, sector_num, buf, n * BDRV_SECTOR_SIZE, NULL) < 0)= { - goto fail; + ret =3D -EIO; + break; } } } @@ -646,7 +668,6 @@ static coroutine_fn int qcow_co_readv(BlockDriverState = *bs, int64_t sector_num, buf +=3D n * 512; } =20 -done: qemu_co_mutex_unlock(&s->lock); =20 if (qiov->niov > 1) { @@ -655,10 +676,6 @@ done: } =20 return ret; - -fail: - ret =3D -EIO; - goto done; } =20 static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t secto= r_num, @@ -697,9 +714,12 @@ static coroutine_fn int qcow_co_writev(BlockDriverStat= e *bs, int64_t sector_num, if (n > nb_sectors) { n =3D nb_sectors; } - cluster_offset =3D get_cluster_offset(bs, sector_num << 9, 1, 0, - index_in_cluster, - index_in_cluster + n); + ret =3D get_cluster_offset(bs, sector_num << 9, 1, 0, + index_in_cluster, + index_in_cluster + n, &cluster_offset); + if (ret < 0) { + break; + } if (!cluster_offset || (cluster_offset & 511) !=3D 0) { ret =3D -EIO; break; @@ -995,8 +1015,11 @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint= 64_t offset, goto success; } qemu_co_mutex_lock(&s->lock); - cluster_offset =3D get_cluster_offset(bs, offset, 2, out_len, 0, 0); + ret =3D get_cluster_offset(bs, offset, 2, out_len, 0, 0, &cluster_offs= et); qemu_co_mutex_unlock(&s->lock); + if (ret < 0) { + goto fail; + } if (cluster_offset =3D=3D 0) { ret =3D -EIO; goto fail; --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504706800935443.95078160028254; Wed, 6 Sep 2017 07:06:40 -0700 (PDT) Received: from localhost ([::1]:36284 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpayV-0007vh-M8 for importer@patchew.org; Wed, 06 Sep 2017 10:06:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50145) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavF-0005b3-Fe for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpavE-0000yd-Gl for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:17 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39034) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpauy-0000nP-E3; Wed, 06 Sep 2017 10:03:00 -0400 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 78AADC047B74; Wed, 6 Sep 2017 14:02:59 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 85EE317A60; Wed, 6 Sep 2017 14:02:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 78AADC047B74 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:38 +0200 Message-Id: <20170906140246.7326-7-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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.31]); Wed, 06 Sep 2017 14:02:59 +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] [PULL 06/14] qcow: Check failure of bdrv_getlength() and bdrv_truncate() 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, 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" From: Eric Blake Omitting the check for whether bdrv_getlength() and bdrv_truncate() failed meant that it was theoretically possible to return an incorrect offset to the caller. More likely, conditions for either of these functions to fail would also cause one of our other calls (such as bdrv_pread() or bdrv_pwrite_sync()) to also fail, but auditing that we are safe is difficult compared to just patching things to always forward on the error rather than ignoring it. Use osdep.h macros instead of open-coded rounding while in the area. Reported-by: Markus Armbruster Signed-off-by: Eric Blake Signed-off-by: Kevin Wolf --- block/qcow.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/block/qcow.c b/block/qcow.c index d07bef6306..f450b00cfc 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -357,7 +357,8 @@ static int get_cluster_offset(BlockDriverState *bs, { BDRVQcowState *s =3D bs->opaque; int min_index, i, j, l1_index, l2_index, ret; - uint64_t l2_offset, *l2_table, cluster_offset, tmp; + int64_t l2_offset; + uint64_t *l2_table, cluster_offset, tmp; uint32_t min_count; int new_l2_table; =20 @@ -370,8 +371,11 @@ static int get_cluster_offset(BlockDriverState *bs, return 0; /* allocate a new l2 entry */ l2_offset =3D bdrv_getlength(bs->file->bs); + if (l2_offset < 0) { + return l2_offset; + } /* round to cluster size */ - l2_offset =3D (l2_offset + s->cluster_size - 1) & ~(s->cluster_siz= e - 1); + l2_offset =3D QEMU_ALIGN_UP(l2_offset, s->cluster_size); /* update the L1 entry */ s->l1_table[l1_index] =3D l2_offset; tmp =3D cpu_to_be64(l2_offset); @@ -438,8 +442,10 @@ static int get_cluster_offset(BlockDriverState *bs, return -EIO; } cluster_offset =3D bdrv_getlength(bs->file->bs); - cluster_offset =3D (cluster_offset + s->cluster_size - 1) & - ~(s->cluster_size - 1); + if ((int64_t) cluster_offset < 0) { + return cluster_offset; + } + cluster_offset =3D QEMU_ALIGN_UP(cluster_offset, s->cluster_si= ze); /* write the cluster content */ ret =3D bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, s->cluster_size); @@ -448,12 +454,20 @@ static int get_cluster_offset(BlockDriverState *bs, } } else { cluster_offset =3D bdrv_getlength(bs->file->bs); + if ((int64_t) cluster_offset < 0) { + return cluster_offset; + } if (allocate =3D=3D 1) { /* round to cluster size */ - cluster_offset =3D (cluster_offset + s->cluster_size - 1) & - ~(s->cluster_size - 1); - bdrv_truncate(bs->file, cluster_offset + s->cluster_size, - PREALLOC_MODE_OFF, NULL); + cluster_offset =3D QEMU_ALIGN_UP(cluster_offset, s->cluste= r_size); + if (cluster_offset + s->cluster_size > INT64_MAX) { + return -E2BIG; + } + ret =3D bdrv_truncate(bs->file, cluster_offset + s->cluste= r_size, + PREALLOC_MODE_OFF, NULL); + if (ret < 0) { + return ret; + } /* if encrypted, we must initialize the cluster content which won't be written */ if (bs->encrypted && --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504707065153737.6395629661179; Wed, 6 Sep 2017 07:11:05 -0700 (PDT) Received: from localhost ([::1]:36307 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb2m-00030x-6t for importer@patchew.org; Wed, 06 Sep 2017 10:11:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50224) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavO-0005jB-DE for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpavE-0000z3-V8 for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:26 -0400 Received: from mx1.redhat.com ([209.132.183.28]:34864) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpav1-0000ot-0N; Wed, 06 Sep 2017 10:03:03 -0400 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 F2DBE356D3; Wed, 6 Sep 2017 14:03:01 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id BA3E26E506; Wed, 6 Sep 2017 14:02:59 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com F2DBE356D3 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:39 +0200 Message-Id: <20170906140246.7326-8-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:03:02 +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] [PULL 07/14] block: document semantics of bdrv_co_preadv|pwritev 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, 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" From: "Daniel P. Berrange" Reviewed-by: Stefan Hajnoczi Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Signed-off-by: Kevin Wolf --- include/block/block_int.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/block/block_int.h b/include/block/block_int.h index 223801e4fb..ba4c383393 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -150,12 +150,43 @@ struct BlockDriver { =20 int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); + + /** + * @offset: position in bytes to read at + * @bytes: number of bytes to read + * @qiov: the buffers to fill with read data + * @flags: currently unused, always 0 + * + * @offset and @bytes will be a multiple of 'request_alignment', + * but the length of individual @qiov elements does not have to + * be a multiple. + * + * @bytes will always equal the total size of @qiov, and will be + * no larger than 'max_transfer'. + * + * The buffer in @qiov may point directly to guest memory. + */ int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags); int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags); + /** + * @offset: position in bytes to write at + * @bytes: number of bytes to write + * @qiov: the buffers containing data to write + * @flags: zero or more bits allowed by 'supported_write_flags' + * + * @offset and @bytes will be a multiple of 'request_alignment', + * but the length of individual @qiov elements does not have to + * be a multiple. + * + * @bytes will always equal the total size of @qiov, and will be + * no larger than 'max_transfer'. + * + * The buffer in @qiov may point directly to guest memory. + */ int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags); =20 --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504707205672400.75806989688067; Wed, 6 Sep 2017 07:13:25 -0700 (PDT) Received: from localhost ([::1]:36317 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb52-0004h4-5Z for importer@patchew.org; Wed, 06 Sep 2017 10:13:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50263) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavV-0005nQ-Hl for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpavR-00017B-Ho for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:41662) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpav3-0000qe-Lv; Wed, 06 Sep 2017 10:03:06 -0400 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 AF135800AF; Wed, 6 Sep 2017 14:03:04 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1DAFC18C60; Wed, 6 Sep 2017 14:03:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com AF135800AF Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:40 +0200 Message-Id: <20170906140246.7326-9-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:03:04 +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] [PULL 08/14] block: move ThrottleGroup membership to ThrottleGroupMember 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, 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" From: Manos Pitsidianakis This commit eliminates the 1:1 relationship between BlockBackend and throttle group state. Users will be able to create multiple throttle nodes, each with its own throttle group state, in the future. The throttle group state cannot be per-BlockBackend anymore, it must be per-throttle node. This is done by gathering ThrottleGroup membership details from BlockBackendPublic into ThrottleGroupMember and refactoring existing code to use the structure. Reviewed-by: Alberto Garcia Reviewed-by: Stefan Hajnoczi Signed-off-by: Manos Pitsidianakis Signed-off-by: Kevin Wolf --- include/block/throttle-groups.h | 39 +++++- include/sysemu/block-backend.h | 20 +-- block/block-backend.c | 66 +++++---- block/qapi.c | 8 +- block/throttle-groups.c | 288 ++++++++++++++++++++----------------= ---- blockdev.c | 4 +- tests/test-throttle.c | 53 ++++---- 7 files changed, 252 insertions(+), 226 deletions(-) diff --git a/include/block/throttle-groups.h b/include/block/throttle-group= s.h index d983d34074..1a6bcdae74 100644 --- a/include/block/throttle-groups.h +++ b/include/block/throttle-groups.h @@ -28,19 +28,44 @@ #include "qemu/throttle.h" #include "block/block_int.h" =20 -const char *throttle_group_get_name(BlockBackend *blk); +/* The ThrottleGroupMember structure indicates membership in a ThrottleGro= up + * and holds related data. + */ + +typedef struct ThrottleGroupMember { + /* throttled_reqs_lock protects the CoQueues for throttled requests. = */ + CoMutex throttled_reqs_lock; + CoQueue throttled_reqs[2]; + + /* Nonzero if the I/O limits are currently being ignored; generally + * it is zero. Accessed with atomic operations. + */ + unsigned int io_limits_disabled; + + /* The following fields are protected by the ThrottleGroup lock. + * See the ThrottleGroup documentation for details. + * throttle_state tells us if I/O limits are configured. */ + ThrottleState *throttle_state; + ThrottleTimers throttle_timers; + unsigned pending_reqs[2]; + QLIST_ENTRY(ThrottleGroupMember) round_robin; + +} ThrottleGroupMember; + +const char *throttle_group_get_name(ThrottleGroupMember *tgm); =20 ThrottleState *throttle_group_incref(const char *name); void throttle_group_unref(ThrottleState *ts); =20 -void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg); -void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg); +void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg); +void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *c= fg); =20 -void throttle_group_register_blk(BlockBackend *blk, const char *groupname); -void throttle_group_unregister_blk(BlockBackend *blk); -void throttle_group_restart_blk(BlockBackend *blk); +void throttle_group_register_tgm(ThrottleGroupMember *tgm, + const char *groupname); +void throttle_group_unregister_tgm(ThrottleGroupMember *tgm); +void throttle_group_restart_tgm(ThrottleGroupMember *tgm); =20 -void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk, +void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMembe= r *tgm, unsigned int bytes, bool is_write); =20 diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index aadc733daf..c4e52a5fa3 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -70,24 +70,10 @@ typedef struct BlockDevOps { =20 /* This struct is embedded in (the private) BlockBackend struct and contai= ns * fields that must be public. This is in particular for QLIST_ENTRY() and - * friends so that BlockBackends can be kept in lists outside block-backen= d.c */ + * friends so that BlockBackends can be kept in lists outside block-backen= d.c + * */ typedef struct BlockBackendPublic { - /* throttled_reqs_lock protects the CoQueues for throttled requests. = */ - CoMutex throttled_reqs_lock; - CoQueue throttled_reqs[2]; - - /* Nonzero if the I/O limits are currently being ignored; generally - * it is zero. Accessed with atomic operations. - */ - unsigned int io_limits_disabled; - - /* The following fields are protected by the ThrottleGroup lock. - * See the ThrottleGroup documentation for details. - * throttle_state tells us if I/O limits are configured. */ - ThrottleState *throttle_state; - ThrottleTimers throttle_timers; - unsigned pending_reqs[2]; - QLIST_ENTRY(BlockBackendPublic) round_robin; + ThrottleGroupMember throttle_group_member; } BlockBackendPublic; =20 BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm); diff --git a/block/block-backend.c b/block/block-backend.c index 1031742401..3dacd7eca7 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -273,9 +273,9 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_pe= rm) blk->shared_perm =3D shared_perm; blk_set_enable_write_cache(blk, true); =20 - qemu_co_mutex_init(&blk->public.throttled_reqs_lock); - qemu_co_queue_init(&blk->public.throttled_reqs[0]); - qemu_co_queue_init(&blk->public.throttled_reqs[1]); + qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_l= ock); + qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0= ]); + qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1= ]); block_acct_init(&blk->stats); =20 notifier_list_init(&blk->remove_bs_notifiers); @@ -343,7 +343,7 @@ static void blk_delete(BlockBackend *blk) assert(!blk->refcnt); assert(!blk->name); assert(!blk->dev); - if (blk->public.throttle_state) { + if (blk->public.throttle_group_member.throttle_state) { blk_io_limits_disable(blk); } if (blk->root) { @@ -658,9 +658,12 @@ 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_state) { - throttle_timers_detach_aio_context(&blk->public.throttle_timers); + 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); @@ -682,9 +685,10 @@ 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_state) { + if (blk->public.throttle_group_member.throttle_state) { throttle_timers_attach_aio_context( - &blk->public.throttle_timers, bdrv_get_aio_context(bs)); + &blk->public.throttle_group_member.throttle_timers, + bdrv_get_aio_context(bs)); } =20 return 0; @@ -1046,8 +1050,9 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int= 64_t offset, bdrv_inc_in_flight(bs); =20 /* throttling disk I/O */ - if (blk->public.throttle_state) { - throttle_group_co_io_limits_intercept(blk, bytes, false); + if (blk->public.throttle_group_member.throttle_state) { + throttle_group_co_io_limits_intercept(&blk->public.throttle_group_= member, + bytes, false); } =20 ret =3D bdrv_co_preadv(blk->root, offset, bytes, qiov, flags); @@ -1070,10 +1075,10 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, = int64_t offset, } =20 bdrv_inc_in_flight(bs); - /* throttling disk I/O */ - if (blk->public.throttle_state) { - throttle_group_co_io_limits_intercept(blk, bytes, true); + 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) { @@ -1742,15 +1747,17 @@ static AioContext *blk_aiocb_get_aio_context(BlockA= IOCB *acb) void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) { BlockDriverState *bs =3D blk_bs(blk); + ThrottleTimers *tt; =20 if (bs) { - if (blk->public.throttle_state) { - throttle_timers_detach_aio_context(&blk->public.throttle_timer= s); + if (blk->public.throttle_group_member.throttle_state) { + tt =3D &blk->public.throttle_group_member.throttle_timers; + throttle_timers_detach_aio_context(tt); } bdrv_set_aio_context(bs, new_context); - if (blk->public.throttle_state) { - throttle_timers_attach_aio_context(&blk->public.throttle_timer= s, - new_context); + if (blk->public.throttle_group_member.throttle_state) { + tt =3D &blk->public.throttle_group_member.throttle_timers; + throttle_timers_attach_aio_context(tt, new_context); } } } @@ -1969,33 +1976,34 @@ int blk_commit_all(void) /* throttling disk I/O limits */ void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg) { - throttle_group_config(blk, cfg); + throttle_group_config(&blk->public.throttle_group_member, cfg); } =20 void blk_io_limits_disable(BlockBackend *blk) { - assert(blk->public.throttle_state); + assert(blk->public.throttle_group_member.throttle_state); bdrv_drained_begin(blk_bs(blk)); - throttle_group_unregister_blk(blk); + throttle_group_unregister_tgm(&blk->public.throttle_group_member); bdrv_drained_end(blk_bs(blk)); } =20 /* should be called before blk_set_io_limits if a limit is set */ void blk_io_limits_enable(BlockBackend *blk, const char *group) { - assert(!blk->public.throttle_state); - throttle_group_register_blk(blk, group); + assert(!blk->public.throttle_group_member.throttle_state); + throttle_group_register_tgm(&blk->public.throttle_group_member, group); } =20 void blk_io_limits_update_group(BlockBackend *blk, const char *group) { /* this BB is not part of any group */ - if (!blk->public.throttle_state) { + if (!blk->public.throttle_group_member.throttle_state) { return; } =20 /* this BB is a part of the same group than the one we want */ - if (!g_strcmp0(throttle_group_get_name(blk), group)) { + if (!g_strcmp0(throttle_group_get_name(&blk->public.throttle_group_mem= ber), + group)) { return; } =20 @@ -2017,8 +2025,8 @@ static void blk_root_drained_begin(BdrvChild *child) /* Note that blk->root may not be accessible here yet if we are just * attaching to a BlockDriverState that is drained. Use child instead.= */ =20 - if (atomic_fetch_inc(&blk->public.io_limits_disabled) =3D=3D 0) { - throttle_group_restart_blk(blk); + 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); } } =20 @@ -2027,8 +2035,8 @@ static void blk_root_drained_end(BdrvChild *child) BlockBackend *blk =3D child->opaque; assert(blk->quiesce_counter); =20 - assert(blk->public.io_limits_disabled); - atomic_dec(&blk->public.io_limits_disabled); + assert(blk->public.throttle_group_member.io_limits_disabled); + atomic_dec(&blk->public.throttle_group_member.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 5f1a71f5d2..7fa2437923 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -66,10 +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_state) { + if (blk && blk_get_public(blk)->throttle_group_member.throttle_state) { ThrottleConfig cfg; + BlockBackendPublic *blkp =3D blk_get_public(blk); =20 - throttle_group_get_config(blk, &cfg); + throttle_group_get_config(&blkp->throttle_group_member, &cfg); =20 info->bps =3D cfg.buckets[THROTTLE_BPS_TOTAL].avg; info->bps_rd =3D cfg.buckets[THROTTLE_BPS_READ].avg; @@ -117,7 +118,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *b= lk, info->iops_size =3D cfg.op_size; =20 info->has_group =3D true; - info->group =3D g_strdup(throttle_group_get_name(blk)); + info->group =3D + g_strdup(throttle_group_get_name(&blkp->throttle_group_member)= ); } =20 info->write_threshold =3D bdrv_write_threshold_get(bs); diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 890bfded3f..c8ed16ddf8 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -30,7 +30,7 @@ #include "sysemu/qtest.h" =20 /* The ThrottleGroup structure (with its ThrottleState) is shared - * among different BlockBackends and it's independent from + * among different ThrottleGroupMembers and it's independent from * AioContext, so in order to use it from different threads it needs * its own locking. * @@ -40,26 +40,26 @@ * The whole ThrottleGroup structure is private and invisible to * outside users, that only use it through its ThrottleState. * - * In addition to the ThrottleGroup structure, BlockBackendPublic has + * In addition to the ThrottleGroup structure, ThrottleGroupMember has * fields that need to be accessed by other members of the group and * therefore also need to be protected by this lock. Once a - * BlockBackend is registered in a group those fields can be accessed + * ThrottleGroupMember is registered in a group those fields can be access= ed * by other threads any time. * * Again, all this is handled internally and is mostly transparent to * the outside. The 'throttle_timers' field however has an additional * constraint because it may be temporarily invalid (see for example * blk_set_aio_context()). Therefore in this file a thread will - * access some other BlockBackend's timers only after verifying that - * that BlockBackend has throttled requests in the queue. + * access some other ThrottleGroupMember's timers only after verifying that + * that ThrottleGroupMember has throttled requests in the queue. */ typedef struct ThrottleGroup { char *name; /* This is constant during the lifetime of the group */ =20 QemuMutex lock; /* This lock protects the following four fields */ ThrottleState ts; - QLIST_HEAD(, BlockBackendPublic) head; - BlockBackend *tokens[2]; + QLIST_HEAD(, ThrottleGroupMember) head; + ThrottleGroupMember *tokens[2]; bool any_timer_armed[2]; QEMUClockType clock_type; =20 @@ -140,114 +140,112 @@ void throttle_group_unref(ThrottleState *ts) qemu_mutex_unlock(&throttle_groups_lock); } =20 -/* Get the name from a BlockBackend's ThrottleGroup. The name (and the poi= nter) +/* Get the name from a ThrottleGroupMember's group. The name (and the poin= ter) * is guaranteed to remain constant during the lifetime of the group. * - * @blk: a BlockBackend that is member of a throttling group + * @tgm: a ThrottleGroupMember * @ret: the name of the group. */ -const char *throttle_group_get_name(BlockBackend *blk) +const char *throttle_group_get_name(ThrottleGroupMember *tgm) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleGroup *tg =3D container_of(blkp->throttle_state, ThrottleGroup= , ts); + ThrottleGroup *tg =3D container_of(tgm->throttle_state, ThrottleGroup,= ts); return tg->name; } =20 -/* Return the next BlockBackend in the round-robin sequence, simulating a - * circular list. +/* Return the next ThrottleGroupMember in the round-robin sequence, simula= ting + * a circular list. * * This assumes that tg->lock is held. * - * @blk: the current BlockBackend - * @ret: the next BlockBackend in the sequence + * @tgm: the current ThrottleGroupMember + * @ret: the next ThrottleGroupMember in the sequence */ -static BlockBackend *throttle_group_next_blk(BlockBackend *blk) +static ThrottleGroupMember *throttle_group_next_tgm(ThrottleGroupMember *t= gm) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleState *ts =3D blkp->throttle_state; + ThrottleState *ts =3D tgm->throttle_state; ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); - BlockBackendPublic *next =3D QLIST_NEXT(blkp, round_robin); + ThrottleGroupMember *next =3D QLIST_NEXT(tgm, round_robin); =20 if (!next) { next =3D QLIST_FIRST(&tg->head); } =20 - return blk_by_public(next); + return next; } =20 /* - * Return whether a BlockBackend has pending requests. + * Return whether a ThrottleGroupMember has pending requests. * * This assumes that tg->lock is held. * - * @blk: the BlockBackend - * @is_write: the type of operation (read/write) - * @ret: whether the BlockBackend has pending requests. + * @tgm: the ThrottleGroupMember + * @is_write: the type of operation (read/write) + * @ret: whether the ThrottleGroupMember has pending requests. */ -static inline bool blk_has_pending_reqs(BlockBackend *blk, +static inline bool tgm_has_pending_reqs(ThrottleGroupMember *tgm, bool is_write) { - const BlockBackendPublic *blkp =3D blk_get_public(blk); - return blkp->pending_reqs[is_write]; + return tgm->pending_reqs[is_write]; } =20 -/* Return the next BlockBackend in the round-robin sequence with pending I= /O - * requests. +/* Return the next ThrottleGroupMember in the round-robin sequence with pe= nding + * I/O requests. * * This assumes that tg->lock is held. * - * @blk: the current BlockBackend + * @tgm: the current ThrottleGroupMember * @is_write: the type of operation (read/write) - * @ret: the next BlockBackend with pending requests, or blk if ther= e is - * none. + * @ret: the next ThrottleGroupMember with pending requests, or tgm = if + * there is none. */ -static BlockBackend *next_throttle_token(BlockBackend *blk, bool is_write) +static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm, + bool is_write) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleGroup *tg =3D container_of(blkp->throttle_state, ThrottleGroup= , ts); - BlockBackend *token, *start; + ThrottleState *ts =3D tgm->throttle_state; + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + ThrottleGroupMember *token, *start; =20 start =3D token =3D tg->tokens[is_write]; =20 /* get next bs round in round robin style */ - token =3D throttle_group_next_blk(token); - while (token !=3D start && !blk_has_pending_reqs(token, is_write)) { - token =3D throttle_group_next_blk(token); + token =3D throttle_group_next_tgm(token); + while (token !=3D start && !tgm_has_pending_reqs(token, is_write)) { + token =3D throttle_group_next_tgm(token); } =20 /* If no IO are queued for scheduling on the next round robin token - * then decide the token is the current bs because chances are - * the current bs get the current request queued. + * then decide the token is the current tgm because chances are + * the current tgm got the current request queued. */ - if (token =3D=3D start && !blk_has_pending_reqs(token, is_write)) { - token =3D blk; + if (token =3D=3D start && !tgm_has_pending_reqs(token, is_write)) { + token =3D tgm; } =20 - /* Either we return the original BB, or one with pending requests */ - assert(token =3D=3D blk || blk_has_pending_reqs(token, is_write)); + /* Either we return the original TGM, or one with pending requests */ + assert(token =3D=3D tgm || tgm_has_pending_reqs(token, is_write)); =20 return token; } =20 -/* Check if the next I/O request for a BlockBackend needs to be throttled = or - * not. If there's no timer set in this group, set one and update the token - * accordingly. +/* Check if the next I/O request for a ThrottleGroupMember needs to be + * throttled or not. If there's no timer set in this group, set one and up= date + * the token accordingly. * * This assumes that tg->lock is held. * - * @blk: the current BlockBackend + * @tgm: the current ThrottleGroupMember * @is_write: the type of operation (read/write) * @ret: whether the I/O request needs to be throttled or not */ -static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write) +static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm, + bool is_write) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleState *ts =3D blkp->throttle_state; - ThrottleTimers *tt =3D &blkp->throttle_timers; + ThrottleState *ts =3D tgm->throttle_state; ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + ThrottleTimers *tt =3D &tgm->throttle_timers; bool must_wait; =20 - if (atomic_read(&blkp->io_limits_disabled)) { + if (atomic_read(&tgm->io_limits_disabled)) { return false; } =20 @@ -258,30 +256,29 @@ static bool throttle_group_schedule_timer(BlockBacken= d *blk, bool is_write) =20 must_wait =3D throttle_schedule_timer(ts, tt, is_write); =20 - /* If a timer just got armed, set blk as the current token */ + /* If a timer just got armed, set tgm as the current token */ if (must_wait) { - tg->tokens[is_write] =3D blk; + tg->tokens[is_write] =3D tgm; tg->any_timer_armed[is_write] =3D true; } =20 return must_wait; } =20 -/* Start the next pending I/O request for a BlockBackend. Return whether +/* Start the next pending I/O request for a ThrottleGroupMember. Return wh= ether * any request was actually pending. * - * @blk: the current BlockBackend + * @tgm: the current ThrottleGroupMember * @is_write: the type of operation (read/write) */ -static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk, +static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMemb= er *tgm, bool is_write) { - BlockBackendPublic *blkp =3D blk_get_public(blk); bool ret; =20 - qemu_co_mutex_lock(&blkp->throttled_reqs_lock); - ret =3D qemu_co_queue_next(&blkp->throttled_reqs[is_write]); - qemu_co_mutex_unlock(&blkp->throttled_reqs_lock); + qemu_co_mutex_lock(&tgm->throttled_reqs_lock); + ret =3D qemu_co_queue_next(&tgm->throttled_reqs[is_write]); + qemu_co_mutex_unlock(&tgm->throttled_reqs_lock); =20 return ret; } @@ -290,19 +287,19 @@ static bool coroutine_fn throttle_group_co_restart_qu= eue(BlockBackend *blk, * * This assumes that tg->lock is held. * - * @blk: the current BlockBackend + * @tgm: the current ThrottleGroupMember * @is_write: the type of operation (read/write) */ -static void schedule_next_request(BlockBackend *blk, bool is_write) +static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleGroup *tg =3D container_of(blkp->throttle_state, ThrottleGroup= , ts); + ThrottleState *ts =3D tgm->throttle_state; + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); bool must_wait; - BlockBackend *token; + ThrottleGroupMember *token; =20 /* Check if there's any pending request to schedule next */ - token =3D next_throttle_token(blk, is_write); - if (!blk_has_pending_reqs(token, is_write)) { + token =3D next_throttle_token(tgm, is_write); + if (!tgm_has_pending_reqs(token, is_write)) { return; } =20 @@ -311,12 +308,12 @@ static void schedule_next_request(BlockBackend *blk, = bool is_write) =20 /* If it doesn't have to wait, queue it for immediate execution */ if (!must_wait) { - /* Give preference to requests from the current blk */ + /* Give preference to requests from the current tgm */ if (qemu_in_coroutine() && - throttle_group_co_restart_queue(blk, is_write)) { - token =3D blk; + throttle_group_co_restart_queue(tgm, is_write)) { + token =3D tgm; } else { - ThrottleTimers *tt =3D &blk_get_public(token)->throttle_timers; + ThrottleTimers *tt =3D &token->throttle_timers; int64_t now =3D qemu_clock_get_ns(tg->clock_type); timer_mod(tt->timers[is_write], now); tg->any_timer_armed[is_write] =3D true; @@ -329,76 +326,77 @@ static void schedule_next_request(BlockBackend *blk, = bool is_write) * if necessary, and schedule the next request using a round robin * algorithm. * - * @blk: the current BlockBackend + * @tgm: the current ThrottleGroupMember * @bytes: the number of bytes for this I/O * @is_write: the type of operation (read/write) */ -void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk, +void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMembe= r *tgm, unsigned int bytes, bool is_write) { bool must_wait; - BlockBackend *token; - - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleGroup *tg =3D container_of(blkp->throttle_state, ThrottleGroup= , ts); + ThrottleGroupMember *token; + ThrottleGroup *tg =3D container_of(tgm->throttle_state, ThrottleGroup,= ts); qemu_mutex_lock(&tg->lock); =20 /* First we check if this I/O has to be throttled. */ - token =3D next_throttle_token(blk, is_write); + token =3D next_throttle_token(tgm, is_write); must_wait =3D throttle_group_schedule_timer(token, is_write); =20 /* Wait if there's a timer set or queued requests of this type */ - if (must_wait || blkp->pending_reqs[is_write]) { - blkp->pending_reqs[is_write]++; + if (must_wait || tgm->pending_reqs[is_write]) { + tgm->pending_reqs[is_write]++; qemu_mutex_unlock(&tg->lock); - qemu_co_mutex_lock(&blkp->throttled_reqs_lock); - qemu_co_queue_wait(&blkp->throttled_reqs[is_write], - &blkp->throttled_reqs_lock); - qemu_co_mutex_unlock(&blkp->throttled_reqs_lock); + qemu_co_mutex_lock(&tgm->throttled_reqs_lock); + qemu_co_queue_wait(&tgm->throttled_reqs[is_write], + &tgm->throttled_reqs_lock); + qemu_co_mutex_unlock(&tgm->throttled_reqs_lock); qemu_mutex_lock(&tg->lock); - blkp->pending_reqs[is_write]--; + tgm->pending_reqs[is_write]--; } =20 /* The I/O will be executed, so do the accounting */ - throttle_account(blkp->throttle_state, is_write, bytes); + throttle_account(tgm->throttle_state, is_write, bytes); =20 /* Schedule the next request */ - schedule_next_request(blk, is_write); + schedule_next_request(tgm, is_write); =20 qemu_mutex_unlock(&tg->lock); } =20 typedef struct { - BlockBackend *blk; + ThrottleGroupMember *tgm; bool is_write; } RestartData; =20 static void coroutine_fn throttle_group_restart_queue_entry(void *opaque) { RestartData *data =3D opaque; - BlockBackend *blk =3D data->blk; + ThrottleGroupMember *tgm =3D data->tgm; + ThrottleState *ts =3D tgm->throttle_state; + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); bool is_write =3D data->is_write; - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleGroup *tg =3D container_of(blkp->throttle_state, ThrottleGroup= , ts); bool empty_queue; =20 - empty_queue =3D !throttle_group_co_restart_queue(blk, is_write); + empty_queue =3D !throttle_group_co_restart_queue(tgm, is_write); =20 /* If the request queue was empty then we have to take care of * scheduling the next one */ if (empty_queue) { qemu_mutex_lock(&tg->lock); - schedule_next_request(blk, is_write); + schedule_next_request(tgm, is_write); qemu_mutex_unlock(&tg->lock); } } =20 -static void throttle_group_restart_queue(BlockBackend *blk, bool is_write) +static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is= _write) { + BlockBackendPublic *blkp =3D container_of(tgm, BlockBackendPublic, + throttle_group_member); + BlockBackend *blk =3D blk_by_public(blkp); Coroutine *co; RestartData rd =3D { - .blk =3D blk, + .tgm =3D tgm, .is_write =3D is_write }; =20 @@ -406,13 +404,11 @@ static void throttle_group_restart_queue(BlockBackend= *blk, bool is_write) aio_co_enter(blk_get_aio_context(blk), co); } =20 -void throttle_group_restart_blk(BlockBackend *blk) +void throttle_group_restart_tgm(ThrottleGroupMember *tgm) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - - if (blkp->throttle_state) { - throttle_group_restart_queue(blk, 0); - throttle_group_restart_queue(blk, 1); + if (tgm->throttle_state) { + throttle_group_restart_queue(tgm, 0); + throttle_group_restart_queue(tgm, 1); } } =20 @@ -420,32 +416,30 @@ void throttle_group_restart_blk(BlockBackend *blk) * to throttle_config(), but guarantees atomicity within the * throttling group. * - * @blk: a BlockBackend that is a member of the group + * @tgm: a ThrottleGroupMember that is a member of the group * @cfg: the configuration to set */ -void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg) +void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleState *ts =3D blkp->throttle_state; + ThrottleState *ts =3D tgm->throttle_state; ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); qemu_mutex_lock(&tg->lock); throttle_config(ts, tg->clock_type, cfg); qemu_mutex_unlock(&tg->lock); =20 - throttle_group_restart_blk(blk); + throttle_group_restart_tgm(tgm); } =20 /* Get the throttle configuration from a particular group. Similar to * throttle_get_config(), but guarantees atomicity within the * throttling group. * - * @blk: a BlockBackend that is a member of the group + * @tgm: a ThrottleGroupMember that is a member of the group * @cfg: the configuration will be written here */ -void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg) +void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *c= fg) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleState *ts =3D blkp->throttle_state; + ThrottleState *ts =3D tgm->throttle_state; ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); qemu_mutex_lock(&tg->lock); throttle_get_config(ts, cfg); @@ -461,7 +455,8 @@ void throttle_group_get_config(BlockBackend *blk, Throt= tleConfig *cfg) static void timer_cb(BlockBackend *blk, bool is_write) { BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleState *ts =3D blkp->throttle_state; + ThrottleGroupMember *tgm =3D &blkp->throttle_group_member; + ThrottleState *ts =3D tgm->throttle_state; ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); =20 /* The timer has just been fired, so we can update the flag */ @@ -470,7 +465,7 @@ static void timer_cb(BlockBackend *blk, bool is_write) qemu_mutex_unlock(&tg->lock); =20 /* Run the request that was waiting for this timer */ - throttle_group_restart_queue(blk, is_write); + throttle_group_restart_queue(tgm, is_write); } =20 static void read_timer_cb(void *opaque) @@ -483,32 +478,36 @@ static void write_timer_cb(void *opaque) timer_cb(opaque, true); } =20 -/* Register a BlockBackend in the throttling group, also initializing its - * timers and updating its throttle_state pointer to point to it. If a +/* Register a ThrottleGroupMember from the throttling group, also initiali= zing + * its timers and updating its throttle_state pointer to point to it. If a * throttling group with that name does not exist yet, it will be created. * - * @blk: the BlockBackend to insert + * @tgm: the ThrottleGroupMember to insert * @groupname: the name of the group */ -void throttle_group_register_blk(BlockBackend *blk, const char *groupname) +void throttle_group_register_tgm(ThrottleGroupMember *tgm, + const char *groupname) { int i; - BlockBackendPublic *blkp =3D blk_get_public(blk); + BlockBackendPublic *blkp =3D container_of(tgm, BlockBackendPublic, + throttle_group_member); + BlockBackend *blk =3D blk_by_public(blkp); ThrottleState *ts =3D throttle_group_incref(groupname); ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); - blkp->throttle_state =3D ts; + + tgm->throttle_state =3D ts; =20 qemu_mutex_lock(&tg->lock); - /* If the ThrottleGroup is new set this BlockBackend as the token */ + /* If the ThrottleGroup is new set this ThrottleGroupMember as the tok= en */ for (i =3D 0; i < 2; i++) { if (!tg->tokens[i]) { - tg->tokens[i] =3D blk; + tg->tokens[i] =3D tgm; } } =20 - QLIST_INSERT_HEAD(&tg->head, blkp, round_robin); + QLIST_INSERT_HEAD(&tg->head, tgm, round_robin); =20 - throttle_timers_init(&blkp->throttle_timers, + throttle_timers_init(&tgm->throttle_timers, blk_get_aio_context(blk), tg->clock_type, read_timer_cb, @@ -518,45 +517,46 @@ void throttle_group_register_blk(BlockBackend *blk, c= onst char *groupname) qemu_mutex_unlock(&tg->lock); } =20 -/* Unregister a BlockBackend from its group, removing it from the list, +/* Unregister a ThrottleGroupMember from its group, removing it from the l= ist, * destroying the timers and setting the throttle_state pointer to NULL. * - * The BlockBackend must not have pending throttled requests, so the calle= r has - * to drain them first. + * The ThrottleGroupMember must not have pending throttled requests, so the + * caller has to drain them first. * * The group will be destroyed if it's empty after this operation. * - * @blk: the BlockBackend to remove + * @tgm the ThrottleGroupMember to remove */ -void throttle_group_unregister_blk(BlockBackend *blk) +void throttle_group_unregister_tgm(ThrottleGroupMember *tgm) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleGroup *tg =3D container_of(blkp->throttle_state, ThrottleGroup= , ts); + ThrottleState *ts =3D tgm->throttle_state; + ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); + ThrottleGroupMember *token; int i; =20 - assert(blkp->pending_reqs[0] =3D=3D 0 && blkp->pending_reqs[1] =3D=3D = 0); - assert(qemu_co_queue_empty(&blkp->throttled_reqs[0])); - assert(qemu_co_queue_empty(&blkp->throttled_reqs[1])); + assert(tgm->pending_reqs[0] =3D=3D 0 && tgm->pending_reqs[1] =3D=3D 0); + assert(qemu_co_queue_empty(&tgm->throttled_reqs[0])); + assert(qemu_co_queue_empty(&tgm->throttled_reqs[1])); =20 qemu_mutex_lock(&tg->lock); for (i =3D 0; i < 2; i++) { - if (tg->tokens[i] =3D=3D blk) { - BlockBackend *token =3D throttle_group_next_blk(blk); - /* Take care of the case where this is the last blk in the gro= up */ - if (token =3D=3D blk) { + if (tg->tokens[i] =3D=3D tgm) { + token =3D throttle_group_next_tgm(tgm); + /* Take care of the case where this is the last tgm in the gro= up */ + if (token =3D=3D tgm) { token =3D NULL; } tg->tokens[i] =3D token; } } =20 - /* remove the current blk from the list */ - QLIST_REMOVE(blkp, round_robin); - throttle_timers_destroy(&blkp->throttle_timers); + /* remove the current tgm from the list */ + QLIST_REMOVE(tgm, round_robin); + throttle_timers_destroy(&tgm->throttle_timers); qemu_mutex_unlock(&tg->lock); =20 throttle_group_unref(&tg->ts); - blkp->throttle_state =3D NULL; + tgm->throttle_state =3D NULL; } =20 static void throttle_groups_init(void) diff --git a/blockdev.c b/blockdev.c index 796beaed94..56a6b24a0b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2686,7 +2686,7 @@ 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_state) { + 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 : @@ -2696,7 +2696,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, = Error **errp) } /* Set the new throttling configuration */ blk_set_io_limits(blk, &cfg); - } else if (blk_get_public(blk)->throttle_state) { + } 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); } diff --git a/tests/test-throttle.c b/tests/test-throttle.c index bf7a5a648a..69cc8b18e4 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -669,6 +669,7 @@ 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 */ blk1 =3D blk_new(0, BLK_PERM_ALL); @@ -679,21 +680,25 @@ static void test_groups(void) blkp2 =3D blk_get_public(blk2); blkp3 =3D blk_get_public(blk3); =20 - g_assert(blkp1->throttle_state =3D=3D NULL); - g_assert(blkp2->throttle_state =3D=3D NULL); - g_assert(blkp3->throttle_state =3D=3D NULL); + tgm1 =3D &blkp1->throttle_group_member; + tgm2 =3D &blkp2->throttle_group_member; + tgm3 =3D &blkp3->throttle_group_member; =20 - throttle_group_register_blk(blk1, "bar"); - throttle_group_register_blk(blk2, "foo"); - throttle_group_register_blk(blk3, "bar"); + g_assert(tgm1->throttle_state =3D=3D NULL); + g_assert(tgm2->throttle_state =3D=3D NULL); + g_assert(tgm3->throttle_state =3D=3D NULL); =20 - g_assert(blkp1->throttle_state !=3D NULL); - g_assert(blkp2->throttle_state !=3D NULL); - g_assert(blkp3->throttle_state !=3D NULL); + throttle_group_register_tgm(tgm1, "bar"); + throttle_group_register_tgm(tgm2, "foo"); + throttle_group_register_tgm(tgm3, "bar"); =20 - g_assert(!strcmp(throttle_group_get_name(blk1), "bar")); - g_assert(!strcmp(throttle_group_get_name(blk2), "foo")); - g_assert(blkp1->throttle_state =3D=3D blkp3->throttle_state); + g_assert(tgm1->throttle_state !=3D NULL); + g_assert(tgm2->throttle_state !=3D NULL); + g_assert(tgm3->throttle_state !=3D NULL); + + g_assert(!strcmp(throttle_group_get_name(tgm1), "bar")); + g_assert(!strcmp(throttle_group_get_name(tgm2), "foo")); + g_assert(tgm1->throttle_state =3D=3D tgm3->throttle_state); =20 /* Setting the config of a group member affects the whole group */ throttle_config_init(&cfg1); @@ -701,29 +706,29 @@ static void test_groups(void) cfg1.buckets[THROTTLE_BPS_WRITE].avg =3D 285000; cfg1.buckets[THROTTLE_OPS_READ].avg =3D 20000; cfg1.buckets[THROTTLE_OPS_WRITE].avg =3D 12000; - throttle_group_config(blk1, &cfg1); + throttle_group_config(tgm1, &cfg1); =20 - throttle_group_get_config(blk1, &cfg1); - throttle_group_get_config(blk3, &cfg2); + throttle_group_get_config(tgm1, &cfg1); + throttle_group_get_config(tgm3, &cfg2); g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1))); =20 cfg2.buckets[THROTTLE_BPS_READ].avg =3D 4547; cfg2.buckets[THROTTLE_BPS_WRITE].avg =3D 1349; cfg2.buckets[THROTTLE_OPS_READ].avg =3D 123; cfg2.buckets[THROTTLE_OPS_WRITE].avg =3D 86; - throttle_group_config(blk3, &cfg1); + throttle_group_config(tgm3, &cfg1); =20 - throttle_group_get_config(blk1, &cfg1); - throttle_group_get_config(blk3, &cfg2); + throttle_group_get_config(tgm1, &cfg1); + throttle_group_get_config(tgm3, &cfg2); g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1))); =20 - throttle_group_unregister_blk(blk1); - throttle_group_unregister_blk(blk2); - throttle_group_unregister_blk(blk3); + throttle_group_unregister_tgm(tgm1); + throttle_group_unregister_tgm(tgm2); + throttle_group_unregister_tgm(tgm3); =20 - g_assert(blkp1->throttle_state =3D=3D NULL); - g_assert(blkp2->throttle_state =3D=3D NULL); - g_assert(blkp3->throttle_state =3D=3D NULL); + g_assert(tgm1->throttle_state =3D=3D NULL); + g_assert(tgm2->throttle_state =3D=3D NULL); + g_assert(tgm3->throttle_state =3D=3D NULL); } =20 int main(int argc, char **argv) --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 150470727786520.32244211433317; Wed, 6 Sep 2017 07:14:37 -0700 (PDT) Received: from localhost ([::1]:36320 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb6C-0005hz-MU for importer@patchew.org; Wed, 06 Sep 2017 10:14:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50270) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavW-0005nT-2r for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpavR-000175-Ev for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:34 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39630) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpav6-0000sZ-AD; Wed, 06 Sep 2017 10:03:08 -0400 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 3CCE8C049E31; Wed, 6 Sep 2017 14:03:07 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id EF53318C5B; Wed, 6 Sep 2017 14:03:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 3CCE8C049E31 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:41 +0200 Message-Id: <20170906140246.7326-10-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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.31]); Wed, 06 Sep 2017 14:03:07 +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] [PULL 09/14] block: add aio_context field in ThrottleGroupMember 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, 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" From: Manos Pitsidianakis timer_cb() needs to know about the current Aio context of the throttle request that is woken up. In order to make ThrottleGroupMember backend agnostic, this information is stored in an aio_context field instead of accessing it from BlockBackend. Reviewed-by: Alberto Garcia Reviewed-by: Stefan Hajnoczi Signed-off-by: Manos Pitsidianakis Signed-off-by: Kevin Wolf --- include/block/throttle-groups.h | 7 ++++- block/block-backend.c | 15 ++++------ block/throttle-groups.c | 38 ++++++++++++++++--------- tests/test-throttle.c | 63 +++++++++++++++++++++----------------= ---- 4 files changed, 69 insertions(+), 54 deletions(-) diff --git a/include/block/throttle-groups.h b/include/block/throttle-group= s.h index 1a6bcdae74..a0f27cac63 100644 --- a/include/block/throttle-groups.h +++ b/include/block/throttle-groups.h @@ -33,6 +33,7 @@ */ =20 typedef struct ThrottleGroupMember { + AioContext *aio_context; /* throttled_reqs_lock protects the CoQueues for throttled requests. = */ CoMutex throttled_reqs_lock; CoQueue throttled_reqs[2]; @@ -61,12 +62,16 @@ void throttle_group_config(ThrottleGroupMember *tgm, Th= rottleConfig *cfg); void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *c= fg); =20 void throttle_group_register_tgm(ThrottleGroupMember *tgm, - const char *groupname); + const char *groupname, + AioContext *ctx); void throttle_group_unregister_tgm(ThrottleGroupMember *tgm); void throttle_group_restart_tgm(ThrottleGroupMember *tgm); =20 void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMembe= r *tgm, unsigned int bytes, bool is_write); +void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, + AioContext *new_context); +void throttle_group_detach_aio_context(ThrottleGroupMember *tgm); =20 #endif diff --git a/block/block-backend.c b/block/block-backend.c index 3dacd7eca7..b4acd0f2ae 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1747,18 +1747,14 @@ static AioContext *blk_aiocb_get_aio_context(BlockA= IOCB *acb) void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) { BlockDriverState *bs =3D blk_bs(blk); - ThrottleTimers *tt; + ThrottleGroupMember *tgm =3D &blk->public.throttle_group_member; =20 if (bs) { - if (blk->public.throttle_group_member.throttle_state) { - tt =3D &blk->public.throttle_group_member.throttle_timers; - throttle_timers_detach_aio_context(tt); + if (tgm->throttle_state) { + throttle_group_detach_aio_context(tgm); + throttle_group_attach_aio_context(tgm, new_context); } bdrv_set_aio_context(bs, new_context); - if (blk->public.throttle_group_member.throttle_state) { - tt =3D &blk->public.throttle_group_member.throttle_timers; - throttle_timers_attach_aio_context(tt, new_context); - } } } =20 @@ -1991,7 +1987,8 @@ void blk_io_limits_disable(BlockBackend *blk) void blk_io_limits_enable(BlockBackend *blk, const char *group) { assert(!blk->public.throttle_group_member.throttle_state); - throttle_group_register_tgm(&blk->public.throttle_group_member, group); + throttle_group_register_tgm(&blk->public.throttle_group_member, + group, blk_get_aio_context(blk)); } =20 void blk_io_limits_update_group(BlockBackend *blk, const char *group) diff --git a/block/throttle-groups.c b/block/throttle-groups.c index c8ed16ddf8..3b07b25f39 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -391,9 +391,6 @@ static void coroutine_fn throttle_group_restart_queue_e= ntry(void *opaque) =20 static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is= _write) { - BlockBackendPublic *blkp =3D container_of(tgm, BlockBackendPublic, - throttle_group_member); - BlockBackend *blk =3D blk_by_public(blkp); Coroutine *co; RestartData rd =3D { .tgm =3D tgm, @@ -401,7 +398,7 @@ static void throttle_group_restart_queue(ThrottleGroupM= ember *tgm, bool is_write }; =20 co =3D qemu_coroutine_create(throttle_group_restart_queue_entry, &rd); - aio_co_enter(blk_get_aio_context(blk), co); + aio_co_enter(tgm->aio_context, co); } =20 void throttle_group_restart_tgm(ThrottleGroupMember *tgm) @@ -449,13 +446,11 @@ void throttle_group_get_config(ThrottleGroupMember *t= gm, ThrottleConfig *cfg) /* ThrottleTimers callback. This wakes up a request that was waiting * because it had been throttled. * - * @blk: the BlockBackend whose request had been throttled + * @tgm: the ThrottleGroupMember whose request had been throttled * @is_write: the type of operation (read/write) */ -static void timer_cb(BlockBackend *blk, bool is_write) +static void timer_cb(ThrottleGroupMember *tgm, bool is_write) { - BlockBackendPublic *blkp =3D blk_get_public(blk); - ThrottleGroupMember *tgm =3D &blkp->throttle_group_member; ThrottleState *ts =3D tgm->throttle_state; ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); =20 @@ -484,18 +479,18 @@ static void write_timer_cb(void *opaque) * * @tgm: the ThrottleGroupMember to insert * @groupname: the name of the group + * @ctx: the AioContext to use */ void throttle_group_register_tgm(ThrottleGroupMember *tgm, - const char *groupname) + const char *groupname, + AioContext *ctx) { int i; - BlockBackendPublic *blkp =3D container_of(tgm, BlockBackendPublic, - throttle_group_member); - BlockBackend *blk =3D blk_by_public(blkp); ThrottleState *ts =3D throttle_group_incref(groupname); ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); =20 tgm->throttle_state =3D ts; + tgm->aio_context =3D ctx; =20 qemu_mutex_lock(&tg->lock); /* If the ThrottleGroup is new set this ThrottleGroupMember as the tok= en */ @@ -508,11 +503,11 @@ void throttle_group_register_tgm(ThrottleGroupMember = *tgm, QLIST_INSERT_HEAD(&tg->head, tgm, round_robin); =20 throttle_timers_init(&tgm->throttle_timers, - blk_get_aio_context(blk), + tgm->aio_context, tg->clock_type, read_timer_cb, write_timer_cb, - blk); + tgm); =20 qemu_mutex_unlock(&tg->lock); } @@ -559,6 +554,21 @@ void throttle_group_unregister_tgm(ThrottleGroupMember= *tgm) tgm->throttle_state =3D NULL; } =20 +void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, + AioContext *new_context) +{ + ThrottleTimers *tt =3D &tgm->throttle_timers; + throttle_timers_attach_aio_context(tt, new_context); + tgm->aio_context =3D new_context; +} + +void throttle_group_detach_aio_context(ThrottleGroupMember *tgm) +{ + ThrottleTimers *tt =3D &tgm->throttle_timers; + throttle_timers_detach_aio_context(tt); + tgm->aio_context =3D NULL; +} + static void throttle_groups_init(void) { qemu_mutex_init(&throttle_groups_lock); diff --git a/tests/test-throttle.c b/tests/test-throttle.c index 69cc8b18e4..e3a45cc605 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -24,8 +24,9 @@ static AioContext *ctx; static LeakyBucket bkt; static ThrottleConfig cfg; +static ThrottleGroupMember tgm; static ThrottleState ts; -static ThrottleTimers tt; +static ThrottleTimers *tt; =20 /* useful function */ static bool double_cmp(double x, double y) @@ -153,19 +154,21 @@ static void test_init(void) { int i; =20 + tt =3D &tgm.throttle_timers; + /* fill the structures with crap */ memset(&ts, 1, sizeof(ts)); - memset(&tt, 1, sizeof(tt)); + memset(tt, 1, sizeof(*tt)); =20 /* init structures */ throttle_init(&ts); - throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, + throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); =20 /* check initialized fields */ - g_assert(tt.clock_type =3D=3D QEMU_CLOCK_VIRTUAL); - g_assert(tt.timers[0]); - g_assert(tt.timers[1]); + g_assert(tt->clock_type =3D=3D QEMU_CLOCK_VIRTUAL); + g_assert(tt->timers[0]); + g_assert(tt->timers[1]); =20 /* check other fields where cleared */ g_assert(!ts.previous_leak); @@ -176,18 +179,18 @@ static void test_init(void) g_assert(!ts.cfg.buckets[i].level); } =20 - throttle_timers_destroy(&tt); + throttle_timers_destroy(tt); } =20 static void test_destroy(void) { int i; throttle_init(&ts); - throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, + throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); - throttle_timers_destroy(&tt); + throttle_timers_destroy(tt); for (i =3D 0; i < 2; i++) { - g_assert(!tt.timers[i]); + g_assert(!tt->timers[i]); } } =20 @@ -224,7 +227,7 @@ static void test_config_functions(void) orig_cfg.op_size =3D 1; =20 throttle_init(&ts); - throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, + throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); /* structure reset by throttle_init previous_leak should be null */ g_assert(!ts.previous_leak); @@ -236,7 +239,7 @@ static void test_config_functions(void) /* get back the fixed configuration */ throttle_get_config(&ts, &final_cfg); =20 - throttle_timers_destroy(&tt); + throttle_timers_destroy(tt); =20 g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg =3D=3D 153); g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg =3D=3D 56); @@ -494,45 +497,45 @@ static void test_have_timer(void) { /* zero structures */ memset(&ts, 0, sizeof(ts)); - memset(&tt, 0, sizeof(tt)); + memset(tt, 0, sizeof(*tt)); =20 /* no timer set should return false */ - g_assert(!throttle_timers_are_initialized(&tt)); + g_assert(!throttle_timers_are_initialized(tt)); =20 /* init structures */ throttle_init(&ts); - throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, + throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); =20 /* timer set by init should return true */ - g_assert(throttle_timers_are_initialized(&tt)); + g_assert(throttle_timers_are_initialized(tt)); =20 - throttle_timers_destroy(&tt); + throttle_timers_destroy(tt); } =20 static void test_detach_attach(void) { /* zero structures */ memset(&ts, 0, sizeof(ts)); - memset(&tt, 0, sizeof(tt)); + memset(tt, 0, sizeof(*tt)); =20 /* init the structure */ throttle_init(&ts); - throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, + throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); =20 /* timer set by init should return true */ - g_assert(throttle_timers_are_initialized(&tt)); + g_assert(throttle_timers_are_initialized(tt)); =20 /* timer should no longer exist after detaching */ - throttle_timers_detach_aio_context(&tt); - g_assert(!throttle_timers_are_initialized(&tt)); + throttle_timers_detach_aio_context(tt); + g_assert(!throttle_timers_are_initialized(tt)); =20 /* timer should exist again after attaching */ - throttle_timers_attach_aio_context(&tt, ctx); - g_assert(throttle_timers_are_initialized(&tt)); + throttle_timers_attach_aio_context(tt, ctx); + g_assert(throttle_timers_are_initialized(tt)); =20 - throttle_timers_destroy(&tt); + throttle_timers_destroy(tt); } =20 static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ @@ -561,7 +564,7 @@ static bool do_test_accounting(bool is_ops, /* are we t= esting bps or ops */ cfg.op_size =3D op_size; =20 throttle_init(&ts); - throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, + throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &cfg); =20 @@ -588,7 +591,7 @@ static bool do_test_accounting(bool is_ops, /* are we t= esting bps or ops */ return false; } =20 - throttle_timers_destroy(&tt); + throttle_timers_destroy(tt); =20 return true; } @@ -688,9 +691,9 @@ static void test_groups(void) g_assert(tgm2->throttle_state =3D=3D NULL); g_assert(tgm3->throttle_state =3D=3D NULL); =20 - throttle_group_register_tgm(tgm1, "bar"); - throttle_group_register_tgm(tgm2, "foo"); - throttle_group_register_tgm(tgm3, "bar"); + throttle_group_register_tgm(tgm1, "bar", blk_get_aio_context(blk1)); + throttle_group_register_tgm(tgm2, "foo", blk_get_aio_context(blk2)); + throttle_group_register_tgm(tgm3, "bar", blk_get_aio_context(blk3)); =20 g_assert(tgm1->throttle_state !=3D NULL); g_assert(tgm2->throttle_state !=3D NULL); --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504706891067300.98506541919437; Wed, 6 Sep 2017 07:08:11 -0700 (PDT) Received: from localhost ([::1]:36289 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpazx-0000qV-Uo for importer@patchew.org; Wed, 06 Sep 2017 10:08:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50189) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavJ-0005eh-3y for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpavF-0000zI-6W for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:21 -0400 Received: from mx1.redhat.com ([209.132.183.28]:35500) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpav9-0000uK-2p; Wed, 06 Sep 2017 10:03:11 -0400 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 19E10356F8; Wed, 6 Sep 2017 14:03:10 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7B09C18C5B; Wed, 6 Sep 2017 14:03:07 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 19E10356F8 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:42 +0200 Message-Id: <20170906140246.7326-11-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:03:10 +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] [PULL 10/14] block: tidy ThrottleGroupMember initializations 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, 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" From: Manos Pitsidianakis Move the CoMutex and CoQueue inits inside throttle_group_register_tgm() which is called whenever a ThrottleGroupMember is initialized. There's no need for them to be separate. Reviewed-by: Alberto Garcia Reviewed-by: Stefan Hajnoczi Signed-off-by: Manos Pitsidianakis Signed-off-by: Kevin Wolf --- block/block-backend.c | 3 --- block/throttle-groups.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index b4acd0f2ae..45d9101be3 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -273,9 +273,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_pe= rm) blk->shared_perm =3D shared_perm; blk_set_enable_write_cache(blk, true); =20 - qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_l= ock); - qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0= ]); - qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1= ]); block_acct_init(&blk->stats); =20 notifier_list_init(&blk->remove_bs_notifiers); diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 3b07b25f39..7749cf043f 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -508,6 +508,9 @@ void throttle_group_register_tgm(ThrottleGroupMember *t= gm, read_timer_cb, write_timer_cb, tgm); + qemu_co_mutex_init(&tgm->throttled_reqs_lock); + qemu_co_queue_init(&tgm->throttled_reqs[0]); + qemu_co_queue_init(&tgm->throttled_reqs[1]); =20 qemu_mutex_unlock(&tg->lock); } --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504707241008273.13749596322305; Wed, 6 Sep 2017 07:14:01 -0700 (PDT) Received: from localhost ([::1]:36319 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb5b-0005Bz-Lb for importer@patchew.org; Wed, 06 Sep 2017 10:13:59 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50323) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavb-0005sy-UV for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpavT-00018V-SJ for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:22967) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpavE-0000xt-2E; Wed, 06 Sep 2017 10:03:16 -0400 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 0F0517E424; Wed, 6 Sep 2017 14:03:15 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5891218C5B; Wed, 6 Sep 2017 14:03:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 0F0517E424 Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:43 +0200 Message-Id: <20170906140246.7326-12-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:03:15 +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] [PULL 11/14] block: convert ThrottleGroup to object with QOM 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, 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" From: Manos Pitsidianakis ThrottleGroup is converted to an object. This will allow the future throttle block filter drive easy creation and configuration of throttle groups in QMP and cli. A new QAPI struct, ThrottleLimits, is introduced to provide a shared struct for all throttle configuration needs in QMP. ThrottleGroups can be created via CLI as -object throttle-group,id=3Dfoo,x-iops-total=3D100,x-.. where x-* are individual limit properties. Since we can't add non-scalar properties in -object this interface must be used instead. However, setting these properties must be disabled after initialization because certain combinations of limits are forbidden and thus configuration changes should be done in one transaction. The individual properties will go away when support for non-scalar values in CLI is implemented and thus are marked as experimental. ThrottleGroup also has a `limits` property that uses the ThrottleLimits struct. It can be used to create ThrottleGroups or set the configuration in existing groups as follows: { "execute": "object-add", "arguments": { "qom-type": "throttle-group", "id": "foo", "props" : { "limits": { "iops-total": 100 } } } } { "execute" : "qom-set", "arguments" : { "path" : "foo", "property" : "limits", "value" : { "iops-total" : 99 } } } This also means a group's configuration can be fetched with qom-get. Signed-off-by: Manos Pitsidianakis Reviewed-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Signed-off-by: Kevin Wolf --- qapi/block-core.json | 48 +++++ include/block/throttle-groups.h | 3 + include/qemu/throttle-options.h | 59 ++++-- include/qemu/throttle.h | 3 + block/throttle-groups.c | 424 ++++++++++++++++++++++++++++++++++++= ---- tests/test-throttle.c | 1 + util/throttle.c | 151 ++++++++++++++ 7 files changed, 628 insertions(+), 61 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 28abb9e6cf..60bd7ec379 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1906,6 +1906,54 @@ '*iops_size': 'int', '*group': 'str' } } =20 ## +# @ThrottleLimits: +# +# Limit parameters for throttling. +# Since some limit combinations are illegal, limits should always be set i= n one +# transaction. All fields are optional. When setting limits, if a field is +# missing the current value is not changed. +# +# @iops-total: limit total I/O operations per second +# @iops-total-max: I/O operations burst +# @iops-total-max-length: length of the iops-total-max burst period, in s= econds +# It must only be set if @iops-total-max is set a= s well. +# @iops-read: limit read operations per second +# @iops-read-max: I/O operations read burst +# @iops-read-max-length: length of the iops-read-max burst period, in se= conds +# It must only be set if @iops-read-max is set as= well. +# @iops-write: limit write operations per second +# @iops-write-max: I/O operations write burst +# @iops-write-max-length: length of the iops-write-max burst period, in s= econds +# It must only be set if @iops-write-max is set a= s well. +# @bps-total: limit total bytes per second +# @bps-total-max: total bytes burst +# @bps-total-max-length: length of the bps-total-max burst period, in se= conds. +# It must only be set if @bps-total-max is set as= well. +# @bps-read: limit read bytes per second +# @bps-read-max: total bytes read burst +# @bps-read-max-length: length of the bps-read-max burst period, in sec= onds +# It must only be set if @bps-read-max is set as = well. +# @bps-write: limit write bytes per second +# @bps-write-max: total bytes write burst +# @bps-write-max-length: length of the bps-write-max burst period, in se= conds +# It must only be set if @bps-write-max is set as= well. +# @iops-size: when limiting by iops max size of an I/O in byt= es +# +# Since: 2.11 +## +{ 'struct': 'ThrottleLimits', + 'data': { '*iops-total' : 'int', '*iops-total-max' : 'int', + '*iops-total-max-length' : 'int', '*iops-read' : 'int', + '*iops-read-max' : 'int', '*iops-read-max-length' : 'int', + '*iops-write' : 'int', '*iops-write-max' : 'int', + '*iops-write-max-length' : 'int', '*bps-total' : 'int', + '*bps-total-max' : 'int', '*bps-total-max-length' : 'int', + '*bps-read' : 'int', '*bps-read-max' : 'int', + '*bps-read-max-length' : 'int', '*bps-write' : 'int', + '*bps-write-max' : 'int', '*bps-write-max-length' : 'int', + '*iops-size' : 'int' } } + +## # @block-stream: # # Copy data from a backing file into a block device. diff --git a/include/block/throttle-groups.h b/include/block/throttle-group= s.h index a0f27cac63..82f030523f 100644 --- a/include/block/throttle-groups.h +++ b/include/block/throttle-groups.h @@ -53,6 +53,9 @@ typedef struct ThrottleGroupMember { =20 } ThrottleGroupMember; =20 +#define TYPE_THROTTLE_GROUP "throttle-group" +#define THROTTLE_GROUP(obj) OBJECT_CHECK(ThrottleGroup, (obj), TYPE_THROTT= LE_GROUP) + const char *throttle_group_get_name(ThrottleGroupMember *tgm); =20 ThrottleState *throttle_group_incref(const char *name); diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-option= s.h index 3133d1ca40..182b7896e1 100644 --- a/include/qemu/throttle-options.h +++ b/include/qemu/throttle-options.h @@ -10,81 +10,102 @@ #ifndef THROTTLE_OPTIONS_H #define THROTTLE_OPTIONS_H =20 +#define QEMU_OPT_IOPS_TOTAL "iops-total" +#define QEMU_OPT_IOPS_TOTAL_MAX "iops-total-max" +#define QEMU_OPT_IOPS_TOTAL_MAX_LENGTH "iops-total-max-length" +#define QEMU_OPT_IOPS_READ "iops-read" +#define QEMU_OPT_IOPS_READ_MAX "iops-read-max" +#define QEMU_OPT_IOPS_READ_MAX_LENGTH "iops-read-max-length" +#define QEMU_OPT_IOPS_WRITE "iops-write" +#define QEMU_OPT_IOPS_WRITE_MAX "iops-write-max" +#define QEMU_OPT_IOPS_WRITE_MAX_LENGTH "iops-write-max-length" +#define QEMU_OPT_BPS_TOTAL "bps-total" +#define QEMU_OPT_BPS_TOTAL_MAX "bps-total-max" +#define QEMU_OPT_BPS_TOTAL_MAX_LENGTH "bps-total-max-length" +#define QEMU_OPT_BPS_READ "bps-read" +#define QEMU_OPT_BPS_READ_MAX "bps-read-max" +#define QEMU_OPT_BPS_READ_MAX_LENGTH "bps-read-max-length" +#define QEMU_OPT_BPS_WRITE "bps-write" +#define QEMU_OPT_BPS_WRITE_MAX "bps-write-max" +#define QEMU_OPT_BPS_WRITE_MAX_LENGTH "bps-write-max-length" +#define QEMU_OPT_IOPS_SIZE "iops-size" + +#define THROTTLE_OPT_PREFIX "throttling." #define THROTTLE_OPTS \ { \ - .name =3D "throttling.iops-total",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "limit total I/O operations per second",\ },{ \ - .name =3D "throttling.iops-read",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "limit read operations per second",\ },{ \ - .name =3D "throttling.iops-write",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "limit write operations per second",\ },{ \ - .name =3D "throttling.bps-total",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "limit total bytes per second",\ },{ \ - .name =3D "throttling.bps-read",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "limit read bytes per second",\ },{ \ - .name =3D "throttling.bps-write",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "limit write bytes per second",\ },{ \ - .name =3D "throttling.iops-total-max",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "I/O operations burst",\ },{ \ - .name =3D "throttling.iops-read-max",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "I/O operations read burst",\ },{ \ - .name =3D "throttling.iops-write-max",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "I/O operations write burst",\ },{ \ - .name =3D "throttling.bps-total-max",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "total bytes burst",\ },{ \ - .name =3D "throttling.bps-read-max",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "total bytes read burst",\ },{ \ - .name =3D "throttling.bps-write-max",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "total bytes write burst",\ },{ \ - .name =3D "throttling.iops-total-max-length",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX_LENGTH,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "length of the iops-total-max burst period, in secon= ds",\ },{ \ - .name =3D "throttling.iops-read-max-length",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX_LENGTH,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "length of the iops-read-max burst period, in second= s",\ },{ \ - .name =3D "throttling.iops-write-max-length",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX_LENGTH,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "length of the iops-write-max burst period, in secon= ds",\ },{ \ - .name =3D "throttling.bps-total-max-length",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX_LENGTH,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "length of the bps-total-max burst period, in second= s",\ },{ \ - .name =3D "throttling.bps-read-max-length",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "length of the bps-read-max burst period, in seconds= ",\ },{ \ - .name =3D "throttling.bps-write-max-length",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX_LENGTH,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "length of the bps-write-max burst period, in second= s",\ },{ \ - .name =3D "throttling.iops-size",\ + .name =3D THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_SIZE,\ .type =3D QEMU_OPT_NUMBER,\ .help =3D "when limiting by iops max size of an I/O in bytes",\ } diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h index 8e01885d29..8c93237866 100644 --- a/include/qemu/throttle.h +++ b/include/qemu/throttle.h @@ -152,5 +152,8 @@ bool throttle_schedule_timer(ThrottleState *ts, bool is_write); =20 void throttle_account(ThrottleState *ts, bool is_write, uint64_t size); +void throttle_limits_to_config(ThrottleLimits *arg, ThrottleConfig *cfg, + Error **errp); +void throttle_config_to_limits(ThrottleConfig *cfg, ThrottleLimits *var); =20 #endif diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 7749cf043f..ed1817ec84 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -25,9 +25,17 @@ #include "qemu/osdep.h" #include "sysemu/block-backend.h" #include "block/throttle-groups.h" +#include "qemu/throttle-options.h" #include "qemu/queue.h" #include "qemu/thread.h" #include "sysemu/qtest.h" +#include "qapi/error.h" +#include "qapi-visit.h" +#include "qom/object.h" +#include "qom/object_interfaces.h" + +static void throttle_group_obj_init(Object *obj); +static void throttle_group_obj_complete(UserCreatable *obj, Error **errp); =20 /* The ThrottleGroup structure (with its ThrottleState) is shared * among different ThrottleGroupMembers and it's independent from @@ -54,6 +62,10 @@ * that ThrottleGroupMember has throttled requests in the queue. */ typedef struct ThrottleGroup { + Object parent_obj; + + /* refuse individual property change if initialization is complete */ + bool is_initialized; char *name; /* This is constant during the lifetime of the group */ =20 QemuMutex lock; /* This lock protects the following four fields */ @@ -63,59 +75,60 @@ typedef struct ThrottleGroup { bool any_timer_armed[2]; QEMUClockType clock_type; =20 - /* These two are protected by the global throttle_groups_lock */ - unsigned refcount; + /* This field is protected by the global QEMU mutex */ QTAILQ_ENTRY(ThrottleGroup) list; } ThrottleGroup; =20 -static QemuMutex throttle_groups_lock; +/* This is protected by the global QEMU mutex */ static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =3D QTAILQ_HEAD_INITIALIZER(throttle_groups); =20 + +/* This function reads throttle_groups and must be called under the global + * mutex. + */ +static ThrottleGroup *throttle_group_by_name(const char *name) +{ + ThrottleGroup *iter; + + /* Look for an existing group with that name */ + QTAILQ_FOREACH(iter, &throttle_groups, list) { + if (!g_strcmp0(name, iter->name)) { + return iter; + } + } + + return NULL; +} + /* Increments the reference count of a ThrottleGroup given its name. * * If no ThrottleGroup is found with the given name a new one is * created. * + * This function edits throttle_groups and must be called under the global + * mutex. + * * @name: the name of the ThrottleGroup * @ret: the ThrottleState member of the ThrottleGroup */ ThrottleState *throttle_group_incref(const char *name) { ThrottleGroup *tg =3D NULL; - ThrottleGroup *iter; - - qemu_mutex_lock(&throttle_groups_lock); =20 /* Look for an existing group with that name */ - QTAILQ_FOREACH(iter, &throttle_groups, list) { - if (!strcmp(name, iter->name)) { - tg =3D iter; - break; - } - } - - /* Create a new one if not found */ - if (!tg) { - tg =3D g_new0(ThrottleGroup, 1); + tg =3D throttle_group_by_name(name); + + if (tg) { + object_ref(OBJECT(tg)); + } else { + /* Create a new one if not found */ + /* new ThrottleGroup obj will have a refcnt =3D 1 */ + tg =3D THROTTLE_GROUP(object_new(TYPE_THROTTLE_GROUP)); tg->name =3D g_strdup(name); - tg->clock_type =3D QEMU_CLOCK_REALTIME; - - if (qtest_enabled()) { - /* For testing block IO throttling only */ - tg->clock_type =3D QEMU_CLOCK_VIRTUAL; - } - qemu_mutex_init(&tg->lock); - throttle_init(&tg->ts); - QLIST_INIT(&tg->head); - - QTAILQ_INSERT_TAIL(&throttle_groups, tg, list); + throttle_group_obj_complete(USER_CREATABLE(tg), &error_abort); } =20 - tg->refcount++; - - qemu_mutex_unlock(&throttle_groups_lock); - return &tg->ts; } =20 @@ -124,20 +137,15 @@ ThrottleState *throttle_group_incref(const char *name) * When the reference count reaches zero the ThrottleGroup is * destroyed. * + * This function edits throttle_groups and must be called under the global + * mutex. + * * @ts: The ThrottleGroup to unref, given by its ThrottleState member */ void throttle_group_unref(ThrottleState *ts) { ThrottleGroup *tg =3D container_of(ts, ThrottleGroup, ts); - - qemu_mutex_lock(&throttle_groups_lock); - if (--tg->refcount =3D=3D 0) { - QTAILQ_REMOVE(&throttle_groups, tg, list); - qemu_mutex_destroy(&tg->lock); - g_free(tg->name); - g_free(tg); - } - qemu_mutex_unlock(&throttle_groups_lock); + object_unref(OBJECT(tg)); } =20 /* Get the name from a ThrottleGroupMember's group. The name (and the poin= ter) @@ -477,6 +485,9 @@ static void write_timer_cb(void *opaque) * its timers and updating its throttle_state pointer to point to it. If a * throttling group with that name does not exist yet, it will be created. * + * This function edits throttle_groups and must be called under the global + * mutex. + * * @tgm: the ThrottleGroupMember to insert * @groupname: the name of the group * @ctx: the AioContext to use @@ -572,9 +583,338 @@ void throttle_group_detach_aio_context(ThrottleGroupM= ember *tgm) tgm->aio_context =3D NULL; } =20 +#undef THROTTLE_OPT_PREFIX +#define THROTTLE_OPT_PREFIX "x-" + +/* Helper struct and array for QOM property setter/getter */ +typedef struct { + const char *name; + BucketType type; + enum { + AVG, + MAX, + BURST_LENGTH, + IOPS_SIZE, + } category; +} ThrottleParamInfo; + +static ThrottleParamInfo properties[] =3D { + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL, + THROTTLE_OPS_TOTAL, AVG, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX, + THROTTLE_OPS_TOTAL, MAX, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX_LENGTH, + THROTTLE_OPS_TOTAL, BURST_LENGTH, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ, + THROTTLE_OPS_READ, AVG, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX, + THROTTLE_OPS_READ, MAX, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX_LENGTH, + THROTTLE_OPS_READ, BURST_LENGTH, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE, + THROTTLE_OPS_WRITE, AVG, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX, + THROTTLE_OPS_WRITE, MAX, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX_LENGTH, + THROTTLE_OPS_WRITE, BURST_LENGTH, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL, + THROTTLE_BPS_TOTAL, AVG, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX, + THROTTLE_BPS_TOTAL, MAX, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX_LENGTH, + THROTTLE_BPS_TOTAL, BURST_LENGTH, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ, + THROTTLE_BPS_READ, AVG, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX, + THROTTLE_BPS_READ, MAX, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH, + THROTTLE_BPS_READ, BURST_LENGTH, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE, + THROTTLE_BPS_WRITE, AVG, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX, + THROTTLE_BPS_WRITE, MAX, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX_LENGTH, + THROTTLE_BPS_WRITE, BURST_LENGTH, + }, + { + THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_SIZE, + 0, IOPS_SIZE, + } +}; + +/* This function edits throttle_groups and must be called under the global + * mutex */ +static void throttle_group_obj_init(Object *obj) +{ + ThrottleGroup *tg =3D THROTTLE_GROUP(obj); + + tg->clock_type =3D QEMU_CLOCK_REALTIME; + if (qtest_enabled()) { + /* For testing block IO throttling only */ + tg->clock_type =3D QEMU_CLOCK_VIRTUAL; + } + tg->is_initialized =3D false; + qemu_mutex_init(&tg->lock); + throttle_init(&tg->ts); + QLIST_INIT(&tg->head); +} + +/* This function edits throttle_groups and must be called under the global + * mutex */ +static void throttle_group_obj_complete(UserCreatable *obj, Error **errp) +{ + ThrottleGroup *tg =3D THROTTLE_GROUP(obj); + ThrottleConfig cfg; + + /* set group name to object id if it exists */ + if (!tg->name && tg->parent_obj.parent) { + tg->name =3D object_get_canonical_path_component(OBJECT(obj)); + } + /* We must have a group name at this point */ + assert(tg->name); + + /* error if name is duplicate */ + if (throttle_group_by_name(tg->name) !=3D NULL) { + error_setg(errp, "A group with this name already exists"); + return; + } + + /* check validity */ + throttle_get_config(&tg->ts, &cfg); + if (!throttle_is_valid(&cfg, errp)) { + return; + } + throttle_config(&tg->ts, tg->clock_type, &cfg); + QTAILQ_INSERT_TAIL(&throttle_groups, tg, list); + tg->is_initialized =3D true; +} + +/* This function edits throttle_groups and must be called under the global + * mutex */ +static void throttle_group_obj_finalize(Object *obj) +{ + ThrottleGroup *tg =3D THROTTLE_GROUP(obj); + if (tg->is_initialized) { + QTAILQ_REMOVE(&throttle_groups, tg, list); + } + qemu_mutex_destroy(&tg->lock); + g_free(tg->name); +} + +static void throttle_group_set(Object *obj, Visitor *v, const char * name, + void *opaque, Error **errp) + +{ + ThrottleGroup *tg =3D THROTTLE_GROUP(obj); + ThrottleConfig *cfg; + ThrottleParamInfo *info =3D opaque; + Error *local_err =3D NULL; + int64_t value; + + /* If we have finished initialization, don't accept individual property + * changes through QOM. Throttle configuration limits must be set in o= ne + * transaction, as certain combinations are invalid. + */ + if (tg->is_initialized) { + error_setg(&local_err, "Property cannot be set after initializatio= n"); + goto ret; + } + + visit_type_int64(v, name, &value, &local_err); + if (local_err) { + goto ret; + } + if (value < 0) { + error_setg(&local_err, "Property values cannot be negative"); + goto ret; + } + + cfg =3D &tg->ts.cfg; + switch (info->category) { + case AVG: + cfg->buckets[info->type].avg =3D value; + break; + case MAX: + cfg->buckets[info->type].max =3D value; + break; + case BURST_LENGTH: + if (value > UINT_MAX) { + error_setg(&local_err, "%s value must be in the" + "range [0, %u]", info->name, UINT_MAX); + goto ret; + } + cfg->buckets[info->type].burst_length =3D value; + break; + case IOPS_SIZE: + cfg->op_size =3D value; + break; + } + +ret: + error_propagate(errp, local_err); + return; + +} + +static void throttle_group_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ThrottleGroup *tg =3D THROTTLE_GROUP(obj); + ThrottleConfig cfg; + ThrottleParamInfo *info =3D opaque; + int64_t value; + + throttle_get_config(&tg->ts, &cfg); + switch (info->category) { + case AVG: + value =3D cfg.buckets[info->type].avg; + break; + case MAX: + value =3D cfg.buckets[info->type].max; + break; + case BURST_LENGTH: + value =3D cfg.buckets[info->type].burst_length; + break; + case IOPS_SIZE: + value =3D cfg.op_size; + break; + } + + visit_type_int64(v, name, &value, errp); +} + +static void throttle_group_set_limits(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) + +{ + ThrottleGroup *tg =3D THROTTLE_GROUP(obj); + ThrottleConfig cfg; + ThrottleLimits arg =3D { 0 }; + ThrottleLimits *argp =3D &arg; + Error *local_err =3D NULL; + + visit_type_ThrottleLimits(v, name, &argp, &local_err); + if (local_err) { + goto ret; + } + qemu_mutex_lock(&tg->lock); + throttle_get_config(&tg->ts, &cfg); + throttle_limits_to_config(argp, &cfg, &local_err); + if (local_err) { + goto unlock; + } + throttle_config(&tg->ts, tg->clock_type, &cfg); + +unlock: + qemu_mutex_unlock(&tg->lock); +ret: + error_propagate(errp, local_err); + return; +} + +static void throttle_group_get_limits(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + ThrottleGroup *tg =3D THROTTLE_GROUP(obj); + ThrottleConfig cfg; + ThrottleLimits arg =3D { 0 }; + ThrottleLimits *argp =3D &arg; + + qemu_mutex_lock(&tg->lock); + throttle_get_config(&tg->ts, &cfg); + qemu_mutex_unlock(&tg->lock); + + throttle_config_to_limits(&cfg, argp); + + visit_type_ThrottleLimits(v, name, &argp, errp); +} + +static bool throttle_group_can_be_deleted(UserCreatable *uc) +{ + return OBJECT(uc)->ref =3D=3D 1; +} + +static void throttle_group_obj_class_init(ObjectClass *klass, void *class_= data) +{ + size_t i =3D 0; + UserCreatableClass *ucc =3D USER_CREATABLE_CLASS(klass); + + ucc->complete =3D throttle_group_obj_complete; + ucc->can_be_deleted =3D throttle_group_can_be_deleted; + + /* individual properties */ + for (i =3D 0; i < sizeof(properties) / sizeof(ThrottleParamInfo); i++)= { + object_class_property_add(klass, + properties[i].name, + "int", + throttle_group_get, + throttle_group_set, + NULL, &properties[i], + &error_abort); + } + + /* ThrottleLimits */ + object_class_property_add(klass, + "limits", "ThrottleLimits", + throttle_group_get_limits, + throttle_group_set_limits, + NULL, NULL, + &error_abort); +} + +static const TypeInfo throttle_group_info =3D { + .name =3D TYPE_THROTTLE_GROUP, + .parent =3D TYPE_OBJECT, + .class_init =3D throttle_group_obj_class_init, + .instance_size =3D sizeof(ThrottleGroup), + .instance_init =3D throttle_group_obj_init, + .instance_finalize =3D throttle_group_obj_finalize, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + }, +}; + static void throttle_groups_init(void) { - qemu_mutex_init(&throttle_groups_lock); + type_register_static(&throttle_group_info); } =20 -block_init(throttle_groups_init); +type_init(throttle_groups_init); diff --git a/tests/test-throttle.c b/tests/test-throttle.c index e3a45cc605..948a42c991 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -739,6 +739,7 @@ int main(int argc, char **argv) qemu_init_main_loop(&error_fatal); ctx =3D qemu_get_aio_context(); bdrv_init(); + module_call_init(MODULE_INIT_QOM); =20 do {} while (g_main_context_iteration(NULL, false)); =20 diff --git a/util/throttle.c b/util/throttle.c index b8c524336c..06bf916adc 100644 --- a/util/throttle.c +++ b/util/throttle.c @@ -484,3 +484,154 @@ void throttle_account(ThrottleState *ts, bool is_writ= e, uint64_t size) } } =20 +/* return a ThrottleConfig based on the options in a ThrottleLimits + * + * @arg: the ThrottleLimits object to read from + * @cfg: the ThrottleConfig to edit + * @errp: error object + */ +void throttle_limits_to_config(ThrottleLimits *arg, ThrottleConfig *cfg, + Error **errp) +{ + if (arg->has_bps_total) { + cfg->buckets[THROTTLE_BPS_TOTAL].avg =3D arg->bps_total; + } + if (arg->has_bps_read) { + cfg->buckets[THROTTLE_BPS_READ].avg =3D arg->bps_read; + } + if (arg->has_bps_write) { + cfg->buckets[THROTTLE_BPS_WRITE].avg =3D arg->bps_write; + } + + if (arg->has_iops_total) { + cfg->buckets[THROTTLE_OPS_TOTAL].avg =3D arg->iops_total; + } + if (arg->has_iops_read) { + cfg->buckets[THROTTLE_OPS_READ].avg =3D arg->iops_read; + } + if (arg->has_iops_write) { + cfg->buckets[THROTTLE_OPS_WRITE].avg =3D arg->iops_write; + } + + if (arg->has_bps_total_max) { + cfg->buckets[THROTTLE_BPS_TOTAL].max =3D arg->bps_total_max; + } + if (arg->has_bps_read_max) { + cfg->buckets[THROTTLE_BPS_READ].max =3D arg->bps_read_max; + } + if (arg->has_bps_write_max) { + cfg->buckets[THROTTLE_BPS_WRITE].max =3D arg->bps_write_max; + } + if (arg->has_iops_total_max) { + cfg->buckets[THROTTLE_OPS_TOTAL].max =3D arg->iops_total_max; + } + if (arg->has_iops_read_max) { + cfg->buckets[THROTTLE_OPS_READ].max =3D arg->iops_read_max; + } + if (arg->has_iops_write_max) { + cfg->buckets[THROTTLE_OPS_WRITE].max =3D arg->iops_write_max; + } + + if (arg->has_bps_total_max_length) { + if (arg->bps_total_max_length > UINT_MAX) { + error_setg(errp, "bps-total-max-length value must be in" + " the range [0, %u]", UINT_MAX); + return; + } + cfg->buckets[THROTTLE_BPS_TOTAL].burst_length =3D arg->bps_total_m= ax_length; + } + if (arg->has_bps_read_max_length) { + if (arg->bps_read_max_length > UINT_MAX) { + error_setg(errp, "bps-read-max-length value must be in" + " the range [0, %u]", UINT_MAX); + return; + } + cfg->buckets[THROTTLE_BPS_READ].burst_length =3D arg->bps_read_max= _length; + } + if (arg->has_bps_write_max_length) { + if (arg->bps_write_max_length > UINT_MAX) { + error_setg(errp, "bps-write-max-length value must be in" + " the range [0, %u]", UINT_MAX); + return; + } + cfg->buckets[THROTTLE_BPS_WRITE].burst_length =3D arg->bps_write_m= ax_length; + } + if (arg->has_iops_total_max_length) { + if (arg->iops_total_max_length > UINT_MAX) { + error_setg(errp, "iops-total-max-length value must be in" + " the range [0, %u]", UINT_MAX); + return; + } + cfg->buckets[THROTTLE_OPS_TOTAL].burst_length =3D arg->iops_total_= max_length; + } + if (arg->has_iops_read_max_length) { + if (arg->iops_read_max_length > UINT_MAX) { + error_setg(errp, "iops-read-max-length value must be in" + " the range [0, %u]", UINT_MAX); + return; + } + cfg->buckets[THROTTLE_OPS_READ].burst_length =3D arg->iops_read_ma= x_length; + } + if (arg->has_iops_write_max_length) { + if (arg->iops_write_max_length > UINT_MAX) { + error_setg(errp, "iops-write-max-length value must be in" + " the range [0, %u]", UINT_MAX); + return; + } + cfg->buckets[THROTTLE_OPS_WRITE].burst_length =3D arg->iops_write_= max_length; + } + + if (arg->has_iops_size) { + cfg->op_size =3D arg->iops_size; + } + + throttle_is_valid(cfg, errp); +} + +/* write the options of a ThrottleConfig to a ThrottleLimits + * + * @cfg: the ThrottleConfig to read from + * @var: the ThrottleLimits to write to + */ +void throttle_config_to_limits(ThrottleConfig *cfg, ThrottleLimits *var) +{ + var->bps_total =3D cfg->buckets[THROTTLE_BPS_TOTAL].avg; + var->bps_read =3D cfg->buckets[THROTTLE_BPS_READ].avg; + var->bps_write =3D cfg->buckets[THROTTLE_BPS_WRITE].avg; + var->iops_total =3D cfg->buckets[THROTTLE_OPS_TOTAL].avg; + var->iops_read =3D cfg->buckets[THROTTLE_OPS_READ].avg; + var->iops_write =3D cfg->buckets[THROTTLE_OPS_WRITE].avg; + var->bps_total_max =3D cfg->buckets[THROTTLE_BPS_TOTAL].max; + var->bps_read_max =3D cfg->buckets[THROTTLE_BPS_READ].max; + var->bps_write_max =3D cfg->buckets[THROTTLE_BPS_WRITE].max; + var->iops_total_max =3D cfg->buckets[THROTTLE_OPS_TOTAL].max; + var->iops_read_max =3D cfg->buckets[THROTTLE_OPS_READ].max; + var->iops_write_max =3D cfg->buckets[THROTTLE_OPS_WRITE].max; + var->bps_total_max_length =3D cfg->buckets[THROTTLE_BPS_TOTAL].burs= t_length; + var->bps_read_max_length =3D cfg->buckets[THROTTLE_BPS_READ].burst= _length; + var->bps_write_max_length =3D cfg->buckets[THROTTLE_BPS_WRITE].burs= t_length; + var->iops_total_max_length =3D cfg->buckets[THROTTLE_OPS_TOTAL].burs= t_length; + var->iops_read_max_length =3D cfg->buckets[THROTTLE_OPS_READ].burst= _length; + var->iops_write_max_length =3D cfg->buckets[THROTTLE_OPS_WRITE].burs= t_length; + var->iops_size =3D cfg->op_size; + + var->has_bps_total =3D true; + var->has_bps_read =3D true; + var->has_bps_write =3D true; + var->has_iops_total =3D true; + var->has_iops_read =3D true; + var->has_iops_write =3D true; + var->has_bps_total_max =3D true; + var->has_bps_read_max =3D true; + var->has_bps_write_max =3D true; + var->has_iops_total_max =3D true; + var->has_iops_read_max =3D true; + var->has_iops_write_max =3D true; + var->has_bps_read_max_length =3D true; + var->has_bps_total_max_length =3D true; + var->has_bps_write_max_length =3D true; + var->has_iops_total_max_length =3D true; + var->has_iops_read_max_length =3D true; + var->has_iops_write_max_length =3D true; + var->has_iops_size =3D true; +} --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504707105056812.712249724019; Wed, 6 Sep 2017 07:11:45 -0700 (PDT) Received: from localhost ([::1]:36308 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb3P-0003U5-Si for importer@patchew.org; Wed, 06 Sep 2017 10:11:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50265) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavV-0005nS-KP for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpavP-00015t-JP for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:34308) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpavJ-00012G-NL; Wed, 06 Sep 2017 10:03:21 -0400 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 C7FE480F75; Wed, 6 Sep 2017 14:03:20 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4895818C5B; Wed, 6 Sep 2017 14:03:15 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com C7FE480F75 Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:44 +0200 Message-Id: <20170906140246.7326-13-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:03:20 +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] [PULL 12/14] block: add throttle block filter driver X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, 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" From: Manos Pitsidianakis block/throttle.c uses existing I/O throttle infrastructure inside a block filter driver. I/O operations are intercepted in the filter's read/write coroutines, and referred to block/throttle-groups.c The driver can be used with the syntax -drive driver=3Dthrottle,file.filename=3Dfoo.qcow2,throttle-group=3Dbar which registers the throttle filter node with the ThrottleGroup 'bar'. The given group must be created beforehand with object-add or -object. Reviewed-by: Alberto Garcia Signed-off-by: Manos Pitsidianakis Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- qapi/block-core.json | 18 ++- include/block/throttle-groups.h | 5 + include/qemu/throttle-options.h | 1 + block/throttle-groups.c | 15 ++- block/throttle.c | 237 ++++++++++++++++++++++++++++++++++++= ++++ block/Makefile.objs | 1 + 6 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 block/throttle.c diff --git a/qapi/block-core.json b/qapi/block-core.json index 60bd7ec379..bb11815608 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2223,6 +2223,7 @@ # Drivers that are supported in block device operations. # # @vxhs: Since 2.10 +# @throttle: Since 2.11 # # Since: 2.9 ## @@ -2232,7 +2233,7 @@ 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh', - 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] } + 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] } =20 ## # @BlockdevOptionsFile: @@ -3096,6 +3097,20 @@ '*tls-creds': 'str' } } =20 ## +# @BlockdevOptionsThrottle: +# +# Driver specific block device options for the throttle driver +# +# @throttle-group: the name of the throttle-group object to use. It +# must already exist. +# @file: reference to or definition of the data source block d= evice +# Since: 2.11 +## +{ 'struct': 'BlockdevOptionsThrottle', + 'data': { 'throttle-group': 'str', + 'file' : 'BlockdevRef' + } } +## # @BlockdevOptions: # # Options for creating a block device. Many options are available for all @@ -3156,6 +3171,7 @@ 'replication':'BlockdevOptionsReplication', 'sheepdog': 'BlockdevOptionsSheepdog', 'ssh': 'BlockdevOptionsSsh', + 'throttle': 'BlockdevOptionsThrottle', 'vdi': 'BlockdevOptionsGenericFormat', 'vhdx': 'BlockdevOptionsGenericFormat', 'vmdk': 'BlockdevOptionsGenericCOWFormat', diff --git a/include/block/throttle-groups.h b/include/block/throttle-group= s.h index 82f030523f..e2fd0513c4 100644 --- a/include/block/throttle-groups.h +++ b/include/block/throttle-groups.h @@ -76,5 +76,10 @@ void coroutine_fn throttle_group_co_io_limits_intercept(= ThrottleGroupMember *tgm void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, AioContext *new_context); void throttle_group_detach_aio_context(ThrottleGroupMember *tgm); +/* + * throttle_group_exists() must be called under the global + * mutex. + */ +bool throttle_group_exists(const char *name); =20 #endif diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-option= s.h index 182b7896e1..3528a8f4a2 100644 --- a/include/qemu/throttle-options.h +++ b/include/qemu/throttle-options.h @@ -29,6 +29,7 @@ #define QEMU_OPT_BPS_WRITE_MAX "bps-write-max" #define QEMU_OPT_BPS_WRITE_MAX_LENGTH "bps-write-max-length" #define QEMU_OPT_IOPS_SIZE "iops-size" +#define QEMU_OPT_THROTTLE_GROUP_NAME "throttle-group" =20 #define THROTTLE_OPT_PREFIX "throttling." #define THROTTLE_OPTS \ diff --git a/block/throttle-groups.c b/block/throttle-groups.c index ed1817ec84..6ba992c8d7 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -101,6 +101,14 @@ static ThrottleGroup *throttle_group_by_name(const cha= r *name) return NULL; } =20 +/* This function reads throttle_groups and must be called under the global + * mutex. + */ +bool throttle_group_exists(const char *name) +{ + return throttle_group_by_name(name) !=3D NULL; +} + /* Increments the reference count of a ThrottleGroup given its name. * * If no ThrottleGroup is found with the given name a new one is @@ -543,6 +551,11 @@ void throttle_group_unregister_tgm(ThrottleGroupMember= *tgm) ThrottleGroupMember *token; int i; =20 + if (!ts) { + /* Discard already unregistered tgm */ + return; + } + assert(tgm->pending_reqs[0] =3D=3D 0 && tgm->pending_reqs[1] =3D=3D 0); assert(qemu_co_queue_empty(&tgm->throttled_reqs[0])); assert(qemu_co_queue_empty(&tgm->throttled_reqs[1])); @@ -709,7 +722,7 @@ static void throttle_group_obj_complete(UserCreatable *= obj, Error **errp) assert(tg->name); =20 /* error if name is duplicate */ - if (throttle_group_by_name(tg->name) !=3D NULL) { + if (throttle_group_exists(tg->name)) { error_setg(errp, "A group with this name already exists"); return; } diff --git a/block/throttle.c b/block/throttle.c new file mode 100644 index 0000000000..5bca76300f --- /dev/null +++ b/block/throttle.c @@ -0,0 +1,237 @@ +/* + * QEMU block throttling filter driver infrastructure + * + * Copyright (c) 2017 Manos Pitsidianakis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "block/throttle-groups.h" +#include "qemu/throttle-options.h" +#include "qapi/error.h" + +static QemuOptsList throttle_opts =3D { + .name =3D "throttle", + .head =3D QTAILQ_HEAD_INITIALIZER(throttle_opts.head), + .desc =3D { + { + .name =3D QEMU_OPT_THROTTLE_GROUP_NAME, + .type =3D QEMU_OPT_STRING, + .help =3D "Name of the throttle group", + }, + { /* end of list */ } + }, +}; + +static int throttle_configure_tgm(BlockDriverState *bs, + ThrottleGroupMember *tgm, + QDict *options, Error **errp) +{ + int ret; + const char *group_name; + Error *local_err =3D NULL; + QemuOpts *opts =3D qemu_opts_create(&throttle_opts, NULL, 0, &error_ab= ort); + + qemu_opts_absorb_qdict(opts, options, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret =3D -EINVAL; + goto fin; + } + + group_name =3D qemu_opt_get(opts, QEMU_OPT_THROTTLE_GROUP_NAME); + if (!group_name) { + error_setg(errp, "Please specify a throttle group"); + ret =3D -EINVAL; + goto fin; + } else if (!throttle_group_exists(group_name)) { + error_setg(errp, "Throttle group '%s' does not exist", group_name); + ret =3D -EINVAL; + goto fin; + } + + /* Register membership to group with name group_name */ + throttle_group_register_tgm(tgm, group_name, bdrv_get_aio_context(bs)); + ret =3D 0; +fin: + qemu_opts_del(opts); + return ret; +} + +static int throttle_open(BlockDriverState *bs, QDict *options, + int flags, Error **errp) +{ + ThrottleGroupMember *tgm =3D bs->opaque; + + bs->file =3D bdrv_open_child(NULL, options, "file", bs, + &child_file, false, errp); + if (!bs->file) { + return -EINVAL; + } + bs->supported_write_flags =3D bs->file->bs->supported_write_flags; + bs->supported_zero_flags =3D bs->file->bs->supported_zero_flags; + + return throttle_configure_tgm(bs, tgm, options, errp); +} + +static void throttle_close(BlockDriverState *bs) +{ + ThrottleGroupMember *tgm =3D bs->opaque; + throttle_group_unregister_tgm(tgm); +} + + +static int64_t throttle_getlength(BlockDriverState *bs) +{ + return bdrv_getlength(bs->file->bs); +} + +static int coroutine_fn throttle_co_preadv(BlockDriverState *bs, + uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, int flags) +{ + + ThrottleGroupMember *tgm =3D bs->opaque; + throttle_group_co_io_limits_intercept(tgm, bytes, false); + + return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); +} + +static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs, + uint64_t offset, uint64_t byte= s, + QEMUIOVector *qiov, int flags) +{ + ThrottleGroupMember *tgm =3D bs->opaque; + throttle_group_co_io_limits_intercept(tgm, bytes, true); + + return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); +} + +static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs, + int64_t offset, int byte= s, + BdrvRequestFlags flags) +{ + ThrottleGroupMember *tgm =3D bs->opaque; + throttle_group_co_io_limits_intercept(tgm, bytes, true); + + return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); +} + +static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs, + int64_t offset, int bytes) +{ + ThrottleGroupMember *tgm =3D bs->opaque; + throttle_group_co_io_limits_intercept(tgm, bytes, true); + + return bdrv_co_pdiscard(bs->file->bs, offset, bytes); +} + +static int throttle_co_flush(BlockDriverState *bs) +{ + return bdrv_co_flush(bs->file->bs); +} + +static void throttle_detach_aio_context(BlockDriverState *bs) +{ + ThrottleGroupMember *tgm =3D bs->opaque; + throttle_group_detach_aio_context(tgm); +} + +static void throttle_attach_aio_context(BlockDriverState *bs, + AioContext *new_context) +{ + ThrottleGroupMember *tgm =3D bs->opaque; + throttle_group_attach_aio_context(tgm, new_context); +} + +static int throttle_reopen_prepare(BDRVReopenState *reopen_state, + BlockReopenQueue *queue, Error **errp) +{ + ThrottleGroupMember *tgm; + + assert(reopen_state !=3D NULL); + assert(reopen_state->bs !=3D NULL); + + reopen_state->opaque =3D g_new0(ThrottleGroupMember, 1); + tgm =3D reopen_state->opaque; + + return throttle_configure_tgm(reopen_state->bs, tgm, reopen_state->opt= ions, + errp); +} + +static void throttle_reopen_commit(BDRVReopenState *reopen_state) +{ + ThrottleGroupMember *old_tgm =3D reopen_state->bs->opaque; + ThrottleGroupMember *new_tgm =3D reopen_state->opaque; + + throttle_group_unregister_tgm(old_tgm); + g_free(old_tgm); + reopen_state->bs->opaque =3D new_tgm; + reopen_state->opaque =3D NULL; +} + +static void throttle_reopen_abort(BDRVReopenState *reopen_state) +{ + ThrottleGroupMember *tgm =3D reopen_state->opaque; + + throttle_group_unregister_tgm(tgm); + g_free(tgm); + reopen_state->opaque =3D NULL; +} + +static bool throttle_recurse_is_first_non_filter(BlockDriverState *bs, + BlockDriverState *candida= te) +{ + return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate); +} + +static BlockDriver bdrv_throttle =3D { + .format_name =3D "throttle", + .protocol_name =3D "throttle", + .instance_size =3D sizeof(ThrottleGroupMember), + + .bdrv_file_open =3D throttle_open, + .bdrv_close =3D throttle_close, + .bdrv_co_flush =3D throttle_co_flush, + + .bdrv_child_perm =3D bdrv_filter_default_perms, + + .bdrv_getlength =3D throttle_getlength, + + .bdrv_co_preadv =3D throttle_co_preadv, + .bdrv_co_pwritev =3D throttle_co_pwritev, + + .bdrv_co_pwrite_zeroes =3D throttle_co_pwrite_zeroes, + .bdrv_co_pdiscard =3D throttle_co_pdiscard, + + .bdrv_recurse_is_first_non_filter =3D throttle_recurse_is_first_no= n_filter, + + .bdrv_attach_aio_context =3D throttle_attach_aio_context, + .bdrv_detach_aio_context =3D throttle_detach_aio_context, + + .bdrv_reopen_prepare =3D throttle_reopen_prepare, + .bdrv_reopen_commit =3D throttle_reopen_commit, + .bdrv_reopen_abort =3D throttle_reopen_abort, + .bdrv_co_get_block_status =3D bdrv_co_get_block_status_fro= m_file, + + .is_filter =3D true, +}; + +static void bdrv_throttle_init(void) +{ + bdrv_register(&bdrv_throttle); +} + +block_init(bdrv_throttle_init); diff --git a/block/Makefile.objs b/block/Makefile.objs index 2aaede4ae1..6eaf78a046 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -25,6 +25,7 @@ block-obj-y +=3D accounting.o dirty-bitmap.o block-obj-y +=3D write-threshold.o block-obj-y +=3D backup.o block-obj-$(CONFIG_REPLICATION) +=3D replication.o +block-obj-y +=3D throttle.o =20 block-obj-y +=3D crypto.o =20 --=20 2.13.5 From nobody Mon Apr 29 13:17:53 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 1504707417655776.7797458087662; Wed, 6 Sep 2017 07:16:57 -0700 (PDT) Received: from localhost ([::1]:36335 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb8S-0007To-Ju for importer@patchew.org; Wed, 06 Sep 2017 10:16:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50373) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavl-00062Y-2K for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpave-0001GG-N5 for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:49 -0400 Received: from mx1.redhat.com ([209.132.183.28]:52870) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpavS-00017F-5N; Wed, 06 Sep 2017 10:03:30 -0400 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 360F752778; Wed, 6 Sep 2017 14:03:29 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 162DF18C5B; Wed, 6 Sep 2017 14:03:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 360F752778 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:45 +0200 Message-Id: <20170906140246.7326-14-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@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]); Wed, 06 Sep 2017 14:03: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] [PULL 13/14] qemu-iotests: add 184 for throttle filter driver X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, 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" From: Manos Pitsidianakis Reviewed-by: Alberto Garcia Signed-off-by: Manos Pitsidianakis Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- tests/qemu-iotests/184 | 205 ++++++++++++++++++++++++++++++ tests/qemu-iotests/184.out | 302 +++++++++++++++++++++++++++++++++++++++++= ++++ tests/qemu-iotests/group | 1 + 3 files changed, 508 insertions(+) create mode 100755 tests/qemu-iotests/184 create mode 100644 tests/qemu-iotests/184.out diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184 new file mode 100755 index 0000000000..704f38f936 --- /dev/null +++ b/tests/qemu-iotests/184 @@ -0,0 +1,205 @@ +#!/bin/bash +# +# Test I/O throttle block filter driver interface +# +# Copyright (C) 2017 Manos Pitsidianakis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# creator +owner=3D"Manos Pitsidianakis" + +seq=3D`basename $0` +echo "QA output created by $seq" + +here=3D`pwd` +status=3D1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +function do_run_qemu() +{ + echo Testing: "$@" | _filter_imgfmt + $QEMU -nographic -qmp-pretty stdio -serial none "$@" + echo +} + +function run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\ + | _filter_qemu_io | _filter_generated_node_ids +} + +_make_test_img 64M +test_throttle=3D$($QEMU_IMG --help|grep throttle) +[ "$test_throttle" =3D "" ] && _supported_fmt throttle + +echo +echo "=3D=3D checking interface =3D=3D" + +run_qemu < Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1504707414035583.3564658304648; Wed, 6 Sep 2017 07:16:54 -0700 (PDT) Received: from localhost ([::1]:36334 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpb8N-0007Qc-T9 for importer@patchew.org; Wed, 06 Sep 2017 10:16:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50413) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dpavq-00067U-GL for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:04:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dpavl-0001KW-QS for qemu-devel@nongnu.org; Wed, 06 Sep 2017 10:03:54 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37338) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dpavX-0001A9-Hb; Wed, 06 Sep 2017 10:03:35 -0400 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 8DC48356FC; Wed, 6 Sep 2017 14:03:34 +0000 (UTC) Received: from dhcp-200-186.str.redhat.com (dhcp-200-186.str.redhat.com [10.33.200.186]) by smtp.corp.redhat.com (Postfix) with ESMTP id 771A918C5B; Wed, 6 Sep 2017 14:03:29 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8DC48356FC Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=kwolf@redhat.com From: Kevin Wolf To: qemu-block@nongnu.org Date: Wed, 6 Sep 2017 16:02:46 +0200 Message-Id: <20170906140246.7326-15-kwolf@redhat.com> In-Reply-To: <20170906140246.7326-1-kwolf@redhat.com> References: <20170906140246.7326-1-kwolf@redhat.com> MIME-Version: 1.0 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]); Wed, 06 Sep 2017 14:03:34 +0000 (UTC) Content-Transfer-Encoding: quoted-printable 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] [PULL 14/14] qcow2: move qcow2_store_persistent_dirty_bitmaps() before cache flushing 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, 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-Type: text/plain; charset="utf-8" From: Pavel Butsykin After calling qcow2_inactivate(), all qcow2 caches must be flushed, but this may not happen, because the last call qcow2_store_persistent_dirty_bitmaps() can lead to marking l2/refcont cache as dirty. Let's move qcow2_store_persistent_dirty_bitmaps() before the ca=D1=81he flu= shing to fix it. Cc: qemu-stable@nongnu.org Signed-off-by: Pavel Butsykin Signed-off-by: Kevin Wolf --- block/qcow2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 2ec399663e..bae5893327 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2036,6 +2036,14 @@ static int qcow2_inactivate(BlockDriverState *bs) int ret, result =3D 0; Error *local_err =3D NULL; =20 + qcow2_store_persistent_dirty_bitmaps(bs, &local_err); + if (local_err !=3D NULL) { + result =3D -EINVAL; + error_report_err(local_err); + error_report("Persistent bitmaps are lost for node '%s'", + bdrv_get_device_or_node_name(bs)); + } + ret =3D qcow2_cache_flush(bs, s->l2_table_cache); if (ret) { result =3D ret; @@ -2050,14 +2058,6 @@ static int qcow2_inactivate(BlockDriverState *bs) strerror(-ret)); } =20 - qcow2_store_persistent_dirty_bitmaps(bs, &local_err); - if (local_err !=3D NULL) { - result =3D -EINVAL; - error_report_err(local_err); - error_report("Persistent bitmaps are lost for node '%s'", - bdrv_get_device_or_node_name(bs)); - } - if (result =3D=3D 0) { qcow2_mark_clean(bs); } --=20 2.13.5