From nobody Mon Feb 9 23:42:35 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.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 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=virtuozzo.com ARC-Seal: i=1; a=rsa-sha256; t=1573828169; cv=none; d=zoho.com; s=zohoarc; b=ST2DCX0GaHVQ1VKzLQkLT/sPAuMqCOsCZ5yyzoS2rpi1xcAePk2qQoh0gzbo9+RaBw7NcVrGIX8HZsJHc9cdqxQ3HYmDdjnt2DgjOS2098W+nS9anDPWGRY9KCke42/NTcYFP4RMNocABjZPDCA+pyGHqP3bhBXKGdX91ZgO0g4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1573828169; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=RhY6fqV0CRXwp3k6oAxQ6zrdC6UqegugEV14LMrcwh8=; b=mERZyk1oF7X+Sx7ip4h0aydX5N6i9RTCKLQ0UB0w2TCRRq85KfE08TEmDnF5+anu+qgA3wUl9jH8m8LpFfsx56fbSgHgBRBy2yQT+w2uR6rZJy3PHsjReE1CfMVdAYAmAlXCKTEiPcis0CQML2XLXgVduQ4JkPrqaPOJHWuS4UY= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 15738281694781019.5542521040021; Fri, 15 Nov 2019 06:29:29 -0800 (PST) Received: from localhost ([::1]:39920 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iVcbH-0003K4-O3 for importer@patchew.org; Fri, 15 Nov 2019 09:29:27 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:59040) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iVcNL-0004eJ-HY for qemu-devel@nongnu.org; Fri, 15 Nov 2019 09:15:04 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iVcNK-0001yD-0s for qemu-devel@nongnu.org; Fri, 15 Nov 2019 09:15:03 -0500 Received: from relay.sw.ru ([185.231.240.75]:47414) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iVcNG-0001ry-J3; Fri, 15 Nov 2019 09:14:58 -0500 Received: from vovaso.qa.sw.ru ([10.94.3.0] helo=kvm.qa.sw.ru) by relay.sw.ru with esmtp (Exim 4.92.3) (envelope-from ) id 1iVcNB-0006WW-NH; Fri, 15 Nov 2019 17:14:54 +0300 From: Vladimir Sementsov-Ogievskiy To: qemu-block@nongnu.org Subject: [RFC 17/24] block/block-copy: add ratelimit to block-copy Date: Fri, 15 Nov 2019 17:14:37 +0300 Message-Id: <20191115141444.24155-18-vsementsov@virtuozzo.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191115141444.24155-1-vsementsov@virtuozzo.com> References: <20191115141444.24155-1-vsementsov@virtuozzo.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 185.231.240.75 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, vsementsov@virtuozzo.com, ehabkost@redhat.com, wencongyang2@huawei.com, xiechanglong.d@gmail.com, armbru@redhat.com, qemu-devel@nongnu.org, jsnow@redhat.com, crosa@redhat.com, den@openvz.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" We are going to directly use one async block-copy operation for backup job, so we need rate limitator. We want to maintain current backup behavior: only background copying is limited and copy-before-write operations only participate in limit calculation. Therefore we need one rate limitator for block-copy state and boolean flag for block-copy call state for actual limitation. Note, that we can't just calculate each chunk in limitator after successful copying: it will not restring starting a lot of async sub-requests which will exceed limit too much. Instead let's use the following scheme on sub-request creation: 1. If at the moment limit is not exceeded, create the request and account it immediately. 2. If at the moment limit is already exceeded, drop create sub-request and handle limit instead (by sleep). With this approach we'll never exceed the limit more than by one sub-request (which pretty much matches current backup behavior). Signed-off-by: Vladimir Sementsov-Ogievskiy --- include/block/block-copy.h | 8 +++++++ block/block-copy.c | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/include/block/block-copy.h b/include/block/block-copy.h index 8fc27156b3..3f9cdc5eb2 100644 --- a/include/block/block-copy.h +++ b/include/block/block-copy.h @@ -59,6 +59,14 @@ BlockCopyCallState *block_copy_async(BlockCopyState *s, int64_t max_chunk, BlockCopyAsyncCallbackFunc cb); =20 +/* + * Set speed limit for block-copy instance. All block-copy operations rela= ted to + * this BlockCopyState will participate in speed calculation, but only + * block_copy_async calls with @ratelimit=3Dtrue will be actually limited. + */ +void block_copy_set_speed(BlockCopyState *s, BlockCopyCallState *call_stat= e, + uint64_t speed); + BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s); void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip); =20 diff --git a/block/block-copy.c b/block/block-copy.c index f28f3b8b6c..091bc044de 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -26,6 +26,7 @@ #define BLOCK_COPY_MAX_BUFFER (1 * MiB) #define BLOCK_COPY_MAX_MEM (128 * MiB) #define BLOCK_COPY_MAX_WORKERS 64 +#define BLOCK_COPY_SLICE_TIME 100000000ULL /* ns */ =20 typedef struct BlockCopyCallState { /* IN parameters */ @@ -34,11 +35,13 @@ typedef struct BlockCopyCallState { int64_t bytes; int max_workers; int64_t max_chunk; + bool ratelimit; BlockCopyAsyncCallbackFunc cb; =20 /* State */ bool failed; bool finished; + QemuCoSleepState *sleep_state; =20 /* OUT parameters */ bool error_is_read; @@ -101,6 +104,9 @@ typedef struct BlockCopyState { void *progress_opaque; =20 SharedResource *mem; + + uint64_t speed; + RateLimit rate_limit; } BlockCopyState; =20 static BlockCopyTask *block_copy_find_task(BlockCopyState *s, @@ -575,6 +581,21 @@ block_copy_dirty_clusters(BlockCopyCallState *call_sta= te) } task->zeroes =3D ret & BDRV_BLOCK_ZERO; =20 + if (s->speed) { + if (call_state->ratelimit) { + uint64_t ns =3D ratelimit_calculate_delay(&s->rate_limit, = 0); + if (ns > 0) { + block_copy_task_end(task, -EAGAIN); + g_free(task); + qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, ns, + &call_state->sleep_state); + continue; + } + } + + ratelimit_calculate_delay(&s->rate_limit, task->bytes); + } + trace_block_copy_process(s, offset); =20 co_get_from_shres(s->mem, task->bytes); @@ -604,6 +625,13 @@ out: return ret < 0 ? ret : found_dirty; } =20 +static void block_copy_kick(BlockCopyCallState *call_state) +{ + if (call_state->sleep_state) { + qemu_co_sleep_wake(call_state->sleep_state); + } +} + static int coroutine_fn block_copy_common(BlockCopyCallState *call_state) { int ret =3D 0; @@ -688,6 +716,7 @@ BlockCopyCallState *block_copy_async(BlockCopyState *s, .s =3D s, .offset =3D offset, .bytes =3D bytes, + .ratelimit =3D ratelimit, .cb =3D cb, .max_workers =3D max_workers ?: BLOCK_COPY_MAX_WORKERS, .max_chunk =3D max_chunk, @@ -711,3 +740,18 @@ void block_copy_set_skip_unallocated(BlockCopyState *s= , bool skip) { s->skip_unallocated =3D skip; } + +void block_copy_set_speed(BlockCopyState *s, BlockCopyCallState *call_stat= e, + uint64_t speed) +{ + uint64_t old_speed =3D s->speed; + + s->speed =3D speed; + if (speed > 0) { + ratelimit_set_speed(&s->rate_limit, speed, BLOCK_COPY_SLICE_TIME); + } + + if (call_state && old_speed && (speed > old_speed || speed =3D=3D 0)) { + block_copy_kick(call_state); + } +} --=20 2.21.0