From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from PA4PR04CU001.outbound.protection.outlook.com (mail-francecentralazon11023076.outbound.protection.outlook.com [40.107.162.76]) by lore.virtuozzo.com (Postfix) with ESMTPS id F3311802A5 for ; Wed, 30 Sep 2026 11:18:03 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=xlkUO7i3IfoFcnNaFqmgHBbNgWz/0iOxsz1Lrxm1VfyS8/LGXXY5pFjDengi4khcYBRsD+II4xBPHOo5oL/JoMUGZsTGwV6QZlbdz6o9+BuuabjgtSGJKkmNZNZEtXTR2GciwWyZId9o45+dLM2ap0pOB/+xwAAXMeAyevGeRDn9pBpxsiMKyhmXAmpEIUk/jLmP5D4mjpHXG3pAzvi9uPXXvAwePVd/83EihToMCrX8ZZquGyIUAlW+c030/PMukb3g1Lb8KrPoOjQeIvgxL5DeJdTp2pILUsliTELIrJgaNzxfBnFLBxz5roE4BZ661mHpUiVCLVW/RSw/2v9mRw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=DbZdY7jUSPgEP3x2DpWi7+RQACTL7Jy1iIfxSU0V7dE=; b=o/L+OcpEBAUtVbSffC1kFotNrDhXYW/z4i2mNgsqwM0BsqcXrn2ZTzGRK8tV7CpFTr2J645AP3xL6UNkqiCa/RbBf/w4ToRgxAfTR9Bq03mb9vmImPn+lgsBIuSebUEW42bU45xe/Ys9ldgpQ4+Zy51v7W3D+1RMl/9SYcajnZwkxNH9WdQl3409kWKl8rYK+Iav+FsAjfE8tN1S7lCJgpaMSeS2OGpyD2etROXE3i4VBrI4ozu+cv4zgl40slZKvVMx4M/71saOdknuaK9GdSKVVbCjPuKJTWKayFDY3ljGLb70H0RIE/UH5sX4rGidk71K1gtWL1qGOmlEHoyE+Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 2a00:1450:4864:31::10) smtp.rcpttodomain=virtuozzo.com smtp.mailfrom=openvz.org; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=openvz.org; dkim=pass (signature was verified) header.d=openvz.org; arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=virtuozzo.onmicrosoft.com; s=selector2-virtuozzo-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=DbZdY7jUSPgEP3x2DpWi7+RQACTL7Jy1iIfxSU0V7dE=; b=B6E9qZH63FTzUtYSYpZ+/tEM+TyJ3US9H+dKhw2AWJmsBUnjdJFY+Q6A7amU3OVtmW81a8jz4JGZc74WwH29ByGJu4YkeyZOs/53yH3X9pIw573TEjRkLkAwbcjNjFsV05m2VRuIsNTEc8awFtESZnrUm2M6sbNhmHAjmu6XeiY= Received: from DU7P189CA0011.EURP189.PROD.OUTLOOK.COM (2603:10a6:10:552::25) by PA4PR08MB6016.eurprd08.prod.outlook.com (2603:10a6:102:e3::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.472.15; Wed, 30 Sep 2026 11:18:01 +0000 Received: from DB1PEPF000509E4.eurprd03.prod.outlook.com (2603:10a6:10:552:cafe::4f) by DU7P189CA0011.outlook.office365.com (2603:10a6:10:552::25) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.472.15 via Frontend Transport; Wed, 30 Sep 2026 11:18:00 +0000 Authentication-Results: spf=pass (sender IP is 2a00:1450:4864:31::10) smtp.mailfrom=openvz.org; dkim=pass (signature was verified) header.d=openvz.org;dmarc=pass action=none header.from=openvz.org; Received-SPF: Pass (protection.outlook.com: domain of openvz.org designates 2a00:1450:4864:31::10 as permitted sender) receiver=protection.outlook.com; client-ip=2a00:1450:4864:31::10; helo=mail-wm2-x10.google.com; pr=C Received: from mail-wm2-x10.google.com (2a00:1450:4864:31::10) by DB1PEPF000509E4.mail.protection.outlook.com (2603:10a6:18:3::616) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.472.14 via Frontend Transport; Wed, 30 Sep 2026 11:17:57 +0000 Received: by mail-wm2-x10.google.com with SMTP id 5b1f17b1804b1-49b912d3920so39080285e9.1 for ; Wed, 30 Sep 2026 04:17:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvz.org; s=google; t=1790767077; x=1791371877; darn=virtuozzo.com; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=DbZdY7jUSPgEP3x2DpWi7+RQACTL7Jy1iIfxSU0V7dE=; b=F3LOm6p7xarSN5UiVs/QaywrhPtzI8mXk9DIREZVWuarXsqhQuz9PtxyKZPApyPMYN qZX3qbYAddf7Cd8+OYaAzV/ToXfhhcwik1boWZfmEMvAXl2uTRt5/GBNw1qNXggQ5RAk Ixy6wG3Kl4c0oMRXRijjl++hB9QpLC4w5e/ukR3K/ps3RW6qif1F7jOMdXae4SdKLBTz LdU+xiMUt0r3/cb1CPvbinYEhabfZ7onb7UsBHotHD20KBweCGL3Ne/cFruPLi4j1ShQ yEm9ouCRCxCzA9zGks4XrucgxJL4mtRIShaKp5/JBhNrIj/orlZlH/rbCVztPm+MUwYX gleA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790767077; x=1791371877; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=DbZdY7jUSPgEP3x2DpWi7+RQACTL7Jy1iIfxSU0V7dE=; b=vhT3nH3PZBkgH0/7O6jwg5NwoQTUedZGBB7sNm1n1JccZy4hZkkBLCC1+Sty1kVrC8 Oc35AjZJ5dYqFtkPBDDzEcDhICgqfUNT/rcQThs/pO9Ed28dCgtwcPw91UWJa897tt0O +mlvUUyCHkcPlw+3cRm6jgjpWLwgaH1qP3QLHFT57KF8UYep2ZmRaJi8/z4P2+hZnnNN x96W0AIvSu7Vh0lj/++Q3HyJUFwxqnpkUZfOg6R/PAN9n130W7Azt0DTs2Ey3Eg/xCGI 52vGAh/8sv7h2+beVcV8CLSPN4M68YIAnApQD+uAx7OWlFkClCWB0xlZpEfQZwRWp314 ROyQ== X-Gm-Message-State: AFuF++kt9xm16M4OITL/7Rr29ek2GaqOiRo81TQ0pGzEgmDqyZt45OVo iwuZngavok0u1T0qZ4VtQCW4kS1Sj1F65dXQE1DrTNA8mul/fzcFCptcCipiXtrPhEwPYX5FH4r +2JrcB2w= X-Gm-Gg: AYBFou3V2Sl9BsxGuILe5ARcGAVNF3o4NKpAQ2mdU/pMEPSDdxtgdV8u9WVRFEWGI0C sjKwyyfNxhrjzgFbxJ1ufORu9XxTw9vUqdCeRR9rjrnUtxAFqzW9sio1oYCrhOAX8du0YypVxfL bBrE3WLT9RI+DM6TuDZdkip4qqWPQ1j2o0jLVKwy37vO+pTHutPNOfUg9pX5BehxaETMaNkfowY CKBlwcenoZJFd/BTjeJpNKSki+/kyW7i7hISD9MuK741LyK27KLVCH64FXioA04Tcrd03482R5p /fIo/k6s2JBMZKyFpq+xGuDKxkGG6y0SLP648Z30k8Ux5Xf3Dx3bRdfZa3xjC8c+gR/SphefZxT dKtNs/id6Mm4lSHPbFdrEpXkH2E9NGzkTerFaYT7zoYxTAb9KP380BfBWUewsmfFF/LgwMe2qtj aa2jpI4w7HyRlZGhlWRARJXGM31et6ODNE7NeGGqclKSB4ck+FLQ4lxTRYfCQTdPLlaZM= X-Received: by 2002:a05:600c:1d0d:b0:4a0:151e:f743 with SMTP id 5b1f17b1804b1-4a01b00fba0mr17671315e9.19.1790767076773; Wed, 30 Sep 2026 04:17:56 -0700 (PDT) Received: from athena.sw.ru ([2a06:5b06:b600:300:c6b8:98e2:93f0:2de6]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4a01cd002bcsm3092365e9.4.2026.09.30.04.17.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Sep 2026 04:17:56 -0700 (PDT) From: "Denis V. Lunev" To: svt-core@virtuozzo.com Cc: andrey.drobyshev@virtuozzo.com, den@virtuozzo.com Subject: [PATCH hci-8.0 9/9] block/block-copy: coalesce write-zeroes tasks #VSTOR-134085 Date: Wed, 30 Sep 2026 13:17:39 +0200 Message-ID: <20260930111739.3866427-10-den@openvz.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260930111739.3866427-1-den@openvz.org> References: <20260930111739.3866427-1-den@openvz.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-EOPAttributedMessage: 0 X-EOPTenantAttributedMessage: 0bc7f26d-0264-416e-a6fc-8352af79c58f:0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DB1PEPF000509E4:EE_|PA4PR08MB6016:EE_ X-MS-Office365-Filtering-Correlation-Id: 3c65022b-e61a-445c-73d1-08df1ee47bd8 X-LD-Processed: 0bc7f26d-0264-416e-a6fc-8352af79c58f,ExtAddr X-MS-Exchange-AtpMessageProperties: SA X-MS-Exchange-SenderADCheck: 0 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|9140799003|48200799018|376014|82310400026|61400799027|6059299003|43022699015|5023799004|22082099003|18002099003|16102099003|55112099003|6133799003|10067099003|5063699009|56012099006; X-Microsoft-Antispam-Message-Info: xxFBrToewo5Rsr2mWzpG465cq6jKX3i74XnILTHd1I/nWlkQ0aqcjOW1kzgNfiPRKQu2sbDr0H7cdZQNOqWjWx9mFlSKC42o2OVBsw0M0a+T8ciLpZYUOLI9Qq0BoVZeU7ve3aJTe6/7naJT8ce89jH4165erT6/S2mGd50PI5K2e/vBqEd9AkSKIvDh83bZkmvh7Eu6NlaBphbqxOFzSKBmLR5t+7c6b8gYzlDDbiemcyCMHFcpiDYAn8GFv5z5NVz/A0a3mTbBMgqlrfl7Ny97jzUMxMzcMGvCNb+/DQeYLrO+sqXjqYcffXZgZ54dAVR/lp66MxK/CnAm8CZnzT1za2n3cCQqPgpxbEgsqmRgBILOpFFV4tCvsywV9+ci0Sct/lkADvUsXjsci53mBJl56M4jKf2Clnf28Orrc1zwNW/mpk5WEM2zpyUoRDmvkf0/FItcire9wF2L3Qz4xG3bYAnMaVL6ZU0CXTg8xB9oSiGtYK46tyu6j0ScAN3wzswBl8wWYhb+EnHiZmoIouBryr3kDvIU54rUjn8juld6cwm20sFj7yGn3dlVjyH+JTG5Y963oTUW+ZYZ8ijZTbmm7eCsXSeNtZAfq7OAMq4DTUvVjR/79EM8dxi23xLdT+2cKMompFw9mlMgVf4i+wSrcPfFGudqriR+yFSrzGGzZhBLlqnlaJ/8q+kCTkh8/+CKbRaVwJ8fJhuKd6oYltPrUPPyHrW4TL0mo3lH4Dq6oqeRBdEYvb82qQ6Gg54IlxuD94WI7Aiw8tJ2l9TL8bmPeJtYfld8yIks+NzaWKMI1aQR24LQSD9vjdm6L9NjlH81AWE/ug3MYG8Y6W5qMXIhMOIH7do07dQO6UjqGAw4J8aT6Z9o4wvxFYHQ3P2W X-Forefront-Antispam-Report: CIP:2a00:1450:4864:31::10;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:mail-wm2-x10.google.com;PTR:mail-wm2-x10.google.com;CAT:NONE;SFS:(13230040)(9140799003)(48200799018)(376014)(82310400026)(61400799027)(6059299003)(43022699015)(5023799004)(22082099003)(18002099003)(16102099003)(55112099003)(6133799003)(10067099003)(5063699009)(56012099006);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: Qrv0gLm3TFGsDxbHtbuSq3YCDbSV4yvsmpZ230W33QqTbVf8kEXkCn8EhlqjH2aSghi10G5ZHKfL57yc2QOqqyP3lWexhe0ZFPA5WKq9z1ykEoGu7PH8iByGDnDeeowbMdLNru4NTBiriT6D6ShmAjxQ8PgVLn3m9t5qdkuuuDXy8koJeelG/dTHZLsAioFKpBGkX1y6Kutfhk9sBqvHkuww3+z6LDBo6YePG+l5t3cUVJSBdE2KfobLoSQdTS4fZUgK8zFHz2uzz+NthmTqtNSleOPvxZ2fukVHFJwdo2tWLUzNljBgsvg+fi+KK4s6h6rd9/Exzwkn/x/JcB+U3EwMwHpjqLCSUfv3uc0CoA6BXlv8Ms2JPPvH+iFt1V4oXpZ2u7afX0EyPu36O83oRbcfXXn5aHjwEB+ap4i9GDUJDkeeYFqbpkB3yo/hmBmw X-ExternalRecipientOutboundConnectors: 0bc7f26d-0264-416e-a6fc-8352af79c58f X-Auto-Response-Suppress: DR, OOF, AutoReply X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2026 11:17:57.5456 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 3c65022b-e61a-445c-73d1-08df1ee47bd8 X-MS-Exchange-CrossTenant-Id: 0bc7f26d-0264-416e-a6fc-8352af79c58f X-MS-Exchange-CrossTenant-AuthSource: DB1PEPF000509E4.eurprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: Internet X-MS-Exchange-Transport-CrossTenantHeadersStamped: PA4PR08MB6016 List-Id: From: Denis V. Lunev Task size was capped to block_copy_chunk_size() regardless of method, which sizes a task by the copy buffer. A write-zeroes task carries no buffer, so that cap only splits one long known-zero run into a crowd of small COPY_WRITE_ZEROES tasks, each with its own request against the target. block_copy_task_create() already decides from zero_bitmap how far a task may run, so add block_copy_widen_zero_area() to that decision: for a write-zeroes task, re-search the dirty area under BDRV_REQUEST_MAX_BYTES instead of the buffer chunk size, and let the existing clamp cut it back to where the zero run ends. That bound is INT_MAX rounded down to a sector, so nothing has aligned it to cluster_size and it is aligned down at the use site. Widening is safe: an overlapping caller waits on the task's BlockReq via reqlist_wait_one() rather than observing it mid-flight. A request that large is only cheap where the target zeroes by metadata. BDRV_REQ_NO_FALLBACK in supported_zero_flags rules out the targets which cannot, qcow2 v2 and iscsi among them, but it is optimistic for the rest: file-posix advertises it at open and only learns from a failing fallocate. So a write-zeroes request asks for it while the target is believed to oblige, which costs nothing when it does. A refusal ends the widening, and the range is written in buffer-sized chunks, as is any task widened before the refusal came. -ENOTSUP says the fast path is unavailable, not that the target wrote nothing, so the range is rewritten whole: zeroes over zeroes change nothing. hci-8.0: 6b1a4754713 made the 056 copy-before-write source read as zeroes. One widened write-zeroes task now covers all of it, and the rate limit only charges a task after it ran, so speed=1 no longer keeps the job alive until the test cancels it. Cap the task with x-perf max-chunk there. Reviewed-by: Andrey Drobyshev Signed-off-by: Denis V. Lunev CC: Vladimir Sementsov-Ogievskiy CC: John Snow CC: Andrey Drobyshev --- block/block-copy.c | 94 ++++++++++++++++++++++++++++++++++++++---- tests/qemu-iotests/056 | 3 +- 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/block/block-copy.c b/block/block-copy.c index a35fba45183..082257da7be 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -161,6 +161,8 @@ typedef struct BlockCopyState { /* State fields that use a thread-safe API */ BdrvDirtyBitmap *copy_bitmap; bool top_mode; + /* Whether a write-zeroes task may widen; see block_copy_write_zeroes(). */ + bool zero_widen; /* atomic */ /* Clusters reading as zero; allocated on demand, frozen once valid. */ HBitmap *zero_bitmap; /* Published only once the scan is done. */ @@ -189,6 +191,34 @@ static int64_t block_copy_chunk_size(BlockCopyState *s) } } +/* + * A write-zeroes task carries no buffer, so it may cover far more than + * block_copy_chunk_size(). Return how far it may run; the caller clamps it + * to where the zero run ends. + */ +static int64_t block_copy_widen_zero_area(BlockCopyState *s, + BlockCopyCallState *call_state, + int64_t offset, int64_t search_end, + int64_t bytes) +{ + int64_t aligned = QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES, + s->cluster_size); + int64_t zero_chunk = MIN_NON_ZERO(MAX(aligned, s->cluster_size), + call_state->max_chunk); + int64_t wide_offset, wide_bytes; + + if (!bdrv_dirty_bitmap_next_dirty_area(s->copy_bitmap, offset, search_end, + zero_chunk, &wide_offset, + &wide_bytes)) { + return bytes; + } + + /* @offset is dirty, so the search cannot have moved past it. */ + assert(wide_offset == offset); + + return wide_bytes; +} + /* * Search for the first dirty area in offset/bytes range and create task at * the beginning of it. @@ -200,6 +230,7 @@ block_copy_task_create(BlockCopyState *s, BlockCopyCallState *call_state, BlockCopyTask *task; BlockCopyMethod method; int64_t max_chunk; + int64_t search_end = offset + bytes; QEMU_LOCK_GUARD(&s->lock); max_chunk = MIN_NON_ZERO(block_copy_chunk_size(s), call_state->max_chunk); @@ -221,6 +252,10 @@ block_copy_task_create(BlockCopyState *s, BlockCopyCallState *call_state, if (hbitmap_get(s->zero_bitmap, offset)) { method = COPY_WRITE_ZEROES; + if (qatomic_read(&s->zero_widen)) { + bytes = block_copy_widen_zero_area(s, call_state, offset, + search_end, bytes); + } boundary = hbitmap_next_zero(s->zero_bitmap, offset, bytes); } else { boundary = hbitmap_next_dirty(s->zero_bitmap, offset, bytes); @@ -481,6 +516,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, .max_transfer = QEMU_ALIGN_DOWN( block_copy_max_transfer(source, target), cluster_size), + .zero_widen = target->bs->supported_zero_flags & BDRV_REQ_NO_FALLBACK, }; s->discard_source = discard_source; @@ -537,6 +573,56 @@ static coroutine_fn int block_copy_task_run(AioTaskPool *pool, return 0; } +/* + * Widening a write-zeroes request only pays off where the target zeroes by + * metadata, so while the target is believed to oblige, a request asks to fail + * instead of falling back to writing the zeroes out. That costs nothing when + * it does oblige, and a refusal ends the widening for the rest of the run. + */ +static int coroutine_fn GRAPH_RDLOCK +block_copy_write_zeroes(BlockCopyState *s, int64_t offset, int64_t bytes, + bool *error_is_read) +{ + BdrvRequestFlags flags = s->write_flags & ~BDRV_REQ_WRITE_COMPRESSED; + int64_t chunk; + int ret = 0; + + if (qatomic_read(&s->zero_widen)) { + ret = bdrv_co_pwrite_zeroes(s->target, offset, bytes, + flags | BDRV_REQ_NO_FALLBACK); + if (ret != -ENOTSUP) { + goto out; + } + + /* Redoing the range is safe: zeroes over zeroes change nothing. */ + qatomic_set(&s->zero_widen, false); + } + + WITH_QEMU_LOCK_GUARD(&s->lock) { + chunk = block_copy_chunk_size(s); + } + + while (bytes) { + int64_t n = MIN(bytes, chunk); + + ret = bdrv_co_pwrite_zeroes(s->target, offset, n, flags); + if (ret < 0) { + break; + } + + offset += n; + bytes -= n; + } + +out: + if (ret < 0) { + trace_block_copy_write_zeroes_fail(s, offset, ret); + *error_is_read = false; + } + + return ret; +} + /* * block_copy_do_copy * @@ -568,13 +654,7 @@ block_copy_do_copy(BlockCopyState *s, int64_t offset, int64_t bytes, switch (*method) { case COPY_WRITE_ZEROES: - ret = bdrv_co_pwrite_zeroes(s->target, offset, nbytes, s->write_flags & - ~BDRV_REQ_WRITE_COMPRESSED); - if (ret < 0) { - trace_block_copy_write_zeroes_fail(s, offset, ret); - *error_is_read = false; - } - return ret; + return block_copy_write_zeroes(s, offset, nbytes, error_is_read); case COPY_RANGE_SMALL: case COPY_RANGE_FULL: diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 index e006d1296d9..72ea28365ea 100755 --- a/tests/qemu-iotests/056 +++ b/tests/qemu-iotests/056 @@ -117,7 +117,8 @@ class TestCopyBeforeWrite(iotests.QMPTestCase): self.vm.pause_drive("drive0") self.vm.cmd('drive-backup', device='drive0', sync='full', target=target_img, - format="file", speed=1) + format="file", speed=1, + x_perf={'max-chunk': 65536}) self.vm.cmd('block-job-pause', device="drive0") # Speed is low enough that this must be an uncopied range, which will # trigger the before write notifier -- 2.53.0