From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from MRWPR03CU001.outbound.protection.outlook.com (mail-francesouthazon11021080.outbound.protection.outlook.com [40.107.130.80]) by lore.virtuozzo.com (Postfix) with ESMTPS id 6788980478 for ; Wed, 30 Sep 2026 11:18:01 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=DTPAmtzaCMVfRYOH59HmvaYPCu6Jw3toOAVeBjXJ+mtRqrVFQa0GdPL2LSzmO80G5S93ndoVYMLEe2lot2wA8zgAqKLTsHurUXhEZpJG7DCsLqLJUuIkmY6gUaMDVvF0Qhm8vn8yCmxSMB3H/f1Y7bynj2WA52ezvWfmyWfzFjT+m22ECMsITHfZoMkptlI//KvAL/CyMidiciU6QV1wuGohVCatyc+lLX+cntjyG1MLQfYNHZOcuADApXw7R/GeIjLFJtXLVhIuclEUcfMoUKsULjwh4BOQsC/q3COYOpZR+Uq5nENG6v2ROejBrw9mQ5hKC3Oi6vIRhmx1DpYbqg== 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=enwx2OELrQeTJ1Td6EE9sfFzOH9eskm6RSus7gY+6Gk=; b=mlAk9mRhemQPTe0sdL4igheeE6qjIJkrktav2iEOc331303LX2dBcnM8zWOq63UF4YKjelMdoAL0mCyGJbacuzoqT1LrMogmMRy6EciiRKgH+/a1aknekX0/v/0FSqn28+2r1yW8nsESv2RrFqF9gLF1K4+AKTtLBwfXKlSZj1CNP3XlIwuiXJBM2rnAYhTYC30hXZGV9sffwZHKSBxbgCIwccgrbEBqn4xHKqAAOWvCYPjBAE+Zt9TIsOKJGlOcYV0EKYySdexmhvEHgJtXMEItSeQNGTzmDVwW7s2iadN97oV1PrlKbUzuZNGCqeJ5FRq4gNyrB82hn9gJLqUo1Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 2a00:1450:4864:31::11) 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=enwx2OELrQeTJ1Td6EE9sfFzOH9eskm6RSus7gY+6Gk=; b=XiuB8sVwzTx3Ka72osw17DMpBuCMIJP4BJqab5FKAnYYLRgLWtNv7RCblPL5Yc1e9b3EDapAOueahuietlDP7WEpm1x21wcfUSpug/6dckC4vgbqea6ojJ2Ugm9L+yyK23/yxlJV1aennq38cYhIqI8s8y0bNKfkai2EBndnJVE= Received: from DUZPR01CA0344.eurprd01.prod.exchangelabs.com (2603:10a6:10:4b8::9) by GV2PR08MB8464.eurprd08.prod.outlook.com (2603:10a6:150:b2::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.472.14; Wed, 30 Sep 2026 11:17:56 +0000 Received: from DB1PEPF000509E6.eurprd03.prod.outlook.com (2603:10a6:10:4b8:cafe::70) by DUZPR01CA0344.outlook.office365.com (2603:10a6:10:4b8::9) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.472.16 via Frontend Transport; Wed, 30 Sep 2026 11:17:56 +0000 Authentication-Results: mx.microsoft.com 1; spf=pass (sender IP is 2a00:1450:4864:31::11) 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::11 as permitted sender) receiver=protection.outlook.com; client-ip=2a00:1450:4864:31::11; helo=mail-wm2-x11.google.com; pr=C Received: from mail-wm2-x11.google.com (2a00:1450:4864:31::11) by DB1PEPF000509E6.mail.protection.outlook.com (2603:10a6:18:3::618) 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:56 +0000 Received: by mail-wm2-x11.google.com with SMTP id 5b1f17b1804b1-49ffbd83a92so32255185e9.0 for ; Wed, 30 Sep 2026 04:17:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvz.org; s=google; t=1790767076; x=1791371876; 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=enwx2OELrQeTJ1Td6EE9sfFzOH9eskm6RSus7gY+6Gk=; b=EpjnHpP+hMw91b3//Vo+j8zYy20JgfF+Bsbnu1yd+PdbP0fOLkUnPPu3b/AEs1jw6c KBxfaPXR7AuOQj8AWXAXDzdsN0xqFjdkDlr/a+9zEeAdr6cmhZ2qchBUFDwPy1XyotM/ iztGri5zW8PMI6TlGWYw9yXOT21Q2jJ0k4KyuSx5Ny7rW8KNNXcybi3h/9WDeTzH/g1r fGu8yPuRTJwoGGcD++5ua5muB6Fvx/GZhs6+/uXgSZv4NERnEy1n1JtmgwLjXj9io3fk uvjtEFGhAhkqLRbiNBC/ilUjiV6QkxgEST3SX5Ix5LlPlCn1rVMUPAe8nSlZq00b6y1c 0K0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790767076; x=1791371876; 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=enwx2OELrQeTJ1Td6EE9sfFzOH9eskm6RSus7gY+6Gk=; b=tjVknH4Ms8bxcZlVKZ69R8uWzEy/AGlnq5xPaCLDprdU4fXTZazLCe+09pmUG2u2SM CIm5lhKPT498Hsw7YUY4ng6YWAUSiPPLz4fzaz8o3hKCGwfATCNr2bmNoadnbUrvdYWv fvdU1lTstSU81jSDQwEt2iwZ4/KhvfDH2rHDB/EHP5AsBeuGUbfHnx5igXmIEPwqAK8O DN4RQs6PsxcUB1O9xKYFsCyiXcYJKUHpDlUyH5asYcOSRWCw2dESK/YRBZuFWyxzsQyP k51fSJPNMcIA5WuS4Kbkq7saxHtYyM9sqNGMjGdM+j7LrzWGHn5XQpc8yICI+Fli4shL xPiw== X-Gm-Message-State: AFuF++lz3gGfU9+p5mPrKRXTZxKO0AjZ9Kkn7TSB7SBQxwoD0Qi9HtrA Zc7XX7cCS39QKyZWaYx0YXSI6TNGtdJZFV8Ld+sUnW16Z1Yxgd1s8Cm98zh8rO/asUsANxqFUZw q+6cnijA= X-Gm-Gg: AYBFou1KJEH+ThVgqcUp+B6iklVcU76S8hMdht4fzQT0wGWJsA0JYy7sW9shMDT0gqg /S1m9c1PPqRBpWhtE6fhCKSDK1jQRpqkPSezdzlIWKHUJm0U9JWdNXSvnvUnmIHTaXICAg38qjS BF++mpXGgmZWLfC/zVD32NYgfLlAFcA3FXx8S5iM1aHGd0ggrgR1rHQEk0MJ9zIveibC0POo4DA Blnjfi+7PFr5mSw5CTQKeCPgauo+ssDt5xyJTEWynqTjwtCXWia0yr+ZwD8MxwiLopIJmQcJ2vL bccVpG8XrmRZMNeKwU2QFaNqzX0BnMUH/HPM+lXt2HQ4L3SmFO0CaCcpRJgXJYpdpm4++fAibQQ XKPqxTGZ9qmKuoseQcADSBhkrznCIVSXqnJdcYh8KqO8En62+rMUC7Z7RI7A9KEiwbAu391pwZ8 dVGHiV6rS6oJxYQam4IExWEUXhSe3P8+yzoPBZ3n54gnMSgR87SlyypgMBiBsA1GK1dyeQGOvJk aEutQ== X-Received: by 2002:a05:600c:3d90:b0:49c:f512:2361 with SMTP id 5b1f17b1804b1-4a01aff257amr19509665e9.14.1790767075690; Wed, 30 Sep 2026 04:17:55 -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.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Sep 2026 04:17:55 -0700 (PDT) From: "Denis V. Lunev" To: svt-core@virtuozzo.com Cc: andrey.drobyshev@virtuozzo.com, den@virtuozzo.com Subject: [PATCH hci-8.0 8/9] block/backup: pre-fill zero_bitmap for full/bitmap #VSTOR-134085 Date: Wed, 30 Sep 2026 13:17:38 +0200 Message-ID: <20260930111739.3866427-9-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: DB1PEPF000509E6:EE_|GV2PR08MB8464:EE_ X-MS-Office365-Filtering-Correlation-Id: 0a38a9c1-db0f-46ab-07d4-08df1ee47a52 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|82310400026|6059299003|9140799003|376014|43022699015|61400799027|48200799018|10067099003|5023799004|56012099006|5063699009|6133799003|55112099003|18002099003|16102099003|22082099003; X-Microsoft-Antispam-Message-Info: C8MXFem8AWWNYH/FL0MN4DzAuQmh8YV5kiMa6NrAI3H2plcKGozbsVtKB9/ItteNRg/Q6YjsE2z5dE4HIMPvxxfOUyoLOUDK+/rV/5QXIMwXQ5KJaisaXYPaboJmn5WaRfB+IFmc6eb0e10kNTqu94awK7YV7LWWQDb3jJ68uqxkTUjzQu9yf8sCYGSUWE3t2GY3wI4Ig3PYKVcjpf2tJ/mHKIucYE7cPFhFSlv2U+GGxxFSZAQFuIIjJfMa+inVecWrZuylx3UUiulJmc4sYruYkyGNsehToDRQpeifpJeGFXokXNRsPXXb8MqF7pQc1F21YWnsWATs19mf1NZIn3qFoPBTY1QL82ThCJLxFTgf0EjxQhrQslpsZg/0KXd8/Abf/J+UH5ifg1h4N5URk4jTQ8U3TLBzoQgTY1LpqeCYGTCkonf+FSsDElRtxKVqlZuD/fCmCOSo4xBrI/+8TWccosB3yhOoZq4CVxy3fxwAqCRB4wM78b/rH+aHvRCY/kL5vD3VJPU8lbAp+NTkgAHFqLi7jPTthJnkXfUcTZfhWaulELyvizNeKJqXdLpCSh2vXDDp+dLr5wL/lIdXkVsNJzhmwCFKuYqXzJ9w7OXYeopYhK/EMv4J+kq9elyIfB6uu555IYzvPKDltvlMFZ0Ke50RLshxEDWZozInG68jrHY+QMgF0hvAR74Bt80zLZ72aeLAGxl4HQuSFhPZ3ndEWDi4wTX6hzpYgA/1fDIlQFCkEAe+NtDmjYLEvbLS5umL8qEZW+GdjUJ4wpVib4/uqconeLQX9clsBoKjnEdKLcihXzFCv5Xlowksk7HIEwsegWjEEIW5a+ifMncL2WoQ2c3m7dz/Dq4gqVtr0SqppzJrE5P0OFvd3nngE4B5uiAAfrwi5znN97DUmmi2CJpoA6sjdswwTLr0aeLpGKNYz7BgGCWaJ/1UZnS2e+Yt X-Forefront-Antispam-Report: CIP:2a00:1450:4864:31::11;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:mail-wm2-x11.google.com;PTR:mail-wm2-x11.google.com;CAT:NONE;SFS:(13230040)(82310400026)(6059299003)(9140799003)(376014)(43022699015)(61400799027)(48200799018)(10067099003)(5023799004)(56012099006)(5063699009)(6133799003)(55112099003)(18002099003)(16102099003)(22082099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: TRSs6a660+u+KF7R7Qt4dRTWcna+TkzCW+1HqK5zxjhztDE9RnzIyp9dpjU4uFX2aauujqFenq5ImsFObb9vFow5oe7PbZPkdHdYNDTdl7OZIyLvKyNcmrKFXzrGZryvQ7I69kcK9MqMq519EtjMuk/uqSLzJE9HkY1huV+GZgoCRmkjw4k8nmwa4BNe+HJorhtf7mvELtDh/yTZTisaZShwCtJFhFzaHUsGu/LdZOAi0ouLpS/M9IXMLKgDuGBRIrcdpejxB65gp7QU/vB/1daCq/SPfrhPOhfcrSr3LiKCn8cTejf4Qr447cDWEkQdZPmJODPQfYHgVP/HVzO1/dgP78+7humERuS0IY4qDSMYMtw7YIuyzhMsiQUaNlErLmM9Z1BwaxmDFwKTlF5Zj3Pch1t6URT6qFKmHc0Z6VMYlZk8S7V1HA++nLCZd4ab 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:56.3435 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 0a38a9c1-db0f-46ab-07d4-08df1ee47a52 X-MS-Exchange-CrossTenant-Id: 0bc7f26d-0264-416e-a6fc-8352af79c58f X-MS-Exchange-CrossTenant-AuthSource: DB1PEPF000509E6.eurprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: Internet X-MS-Exchange-Transport-CrossTenantHeadersStamped: GV2PR08MB8464 List-Id: From: Denis V. Lunev Only sync=top runs an up-front scan, so the previous patch did nothing for the other modes. FULL and BITMAP know their complete copy_bitmap before copying starts, and the same copy-before-write guarantee holds: a cluster still dirty when the copy loop reaches it has not been written since the scan. Add block_copy_calculate_zero_bitmap(), driven one query at a time from backup_scan_source() so the graph rdlock and the pause point are taken per query, and query each confirmed span once however many dirty areas it covers. The scan only fills zero_bitmap and never clears copy_bitmap, so sync=full still writes zeroes for clusters the source never allocated; it just stops re-querying to find that out. Unlike the per-task queries it replaces the scan is serial, so a sparsely dirtied job against a slow source may spend more time here than it saves. The sync=top loop had the same shape, so both fold into backup_scan_source(). sync=none keeps the per-task query. Its bitmap says "anything may be copied", not "this will be copied", and it only ever copies what the guest writes during the fleecing window, so scanning the whole image at attach is the wrong trade. hci-8.0: sync=full already runs block_copy_reset_unallocated() since 6b1a4754713, so it stays on that path and only sync=bitmap moves to block_copy_calculate_zero_bitmap(). Unallocated clusters are not written for sync=full here. Reviewed-by: Andrey Drobyshev Signed-off-by: Denis V. Lunev CC: Vladimir Sementsov-Ogievskiy CC: John Snow CC: Andrey Drobyshev --- block/backup.c | 95 +++++++++++++++++++++++--------------- block/block-copy.c | 41 ++++++++++++++++ include/block/block-copy.h | 4 ++ 3 files changed, 104 insertions(+), 36 deletions(-) diff --git a/block/backup.c b/block/backup.c index 03ad1ad350b..eef4512b8bb 100644 --- a/block/backup.c +++ b/block/backup.c @@ -250,60 +250,83 @@ static void backup_init_bcs_bitmap(BackupBlockJob *job) job_progress_set_remaining(&job->common.job, estimate); } -static int coroutine_fn backup_run(Job *job, Error **errp) +/* + * Walk the source before copying starts: fill zero_bitmap and, for sync=top + * and sync=full, drop the clusters that are not allocated. + */ +static int coroutine_fn backup_scan_source(BackupBlockJob *s) { - BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); - int ret; - - backup_init_bcs_bitmap(s); - - if (s->sync_mode == MIRROR_SYNC_MODE_TOP || - s->sync_mode == MIRROR_SYNC_MODE_FULL) - { - int64_t offset = 0; - int64_t count; + Job *job = &s->common.job; + bool skip = s->sync_mode == MIRROR_SYNC_MODE_TOP || + s->sync_mode == MIRROR_SYNC_MODE_FULL; + int64_t offset, cached_end = 0, count; + int ret = 0; - for (offset = 0; offset < s->len; ) { - if (job_is_cancelled(job)) { - return -ECANCELED; - } + for (offset = 0; offset < s->len; offset += count) { + if (job_is_cancelled(job)) { + return -ECANCELED; + } - job_pause_point(job); + job_pause_point(job); - if (job_is_cancelled(job)) { - return -ECANCELED; - } + if (job_is_cancelled(job)) { + return -ECANCELED; + } - /* rdlock protects the subsequent call to bdrv_is_allocated() */ - bdrv_graph_co_rdlock(); + /* rdlock protects the block-status queries below */ + bdrv_graph_co_rdlock(); + if (skip) { ret = block_copy_reset_unallocated(s->bcs, offset, &count); - bdrv_graph_co_rdunlock(); - if (ret < 0) { - return ret; - } + } else { + block_copy_calculate_zero_bitmap(s->bcs, offset, &cached_end, + &count); + } + bdrv_graph_co_rdunlock(); - offset += count; + if (ret < 0) { + return ret; } - block_copy_set_zero_bitmap_valid(s->bcs); } - if (s->sync_mode == MIRROR_SYNC_MODE_NONE) { + block_copy_set_zero_bitmap_valid(s->bcs); + + return 0; +} + +static int coroutine_fn backup_run(Job *job, Error **errp) +{ + BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); + int ret; + + backup_init_bcs_bitmap(s); + + switch (s->sync_mode) { + case MIRROR_SYNC_MODE_TOP: + case MIRROR_SYNC_MODE_FULL: + case MIRROR_SYNC_MODE_BITMAP: + ret = backup_scan_source(s); + if (ret < 0) { + return ret; + } + break; + + case MIRROR_SYNC_MODE_NONE: /* * All bits are set in bcs bitmap to allow any cluster to be copied. - * This does not actually require them to be copied. + * This does not actually require them to be copied. Yield until the + * job is cancelled and let the before_write notify callback service + * CoW requests. */ while (!job_is_cancelled(job)) { - /* - * Yield until the job is cancelled. We just let our before_write - * notify callback service CoW requests. - */ job_yield(job); } - } else { - return backup_loop(s); + return 0; + + default: + g_assert_not_reached(); } - return 0; + return backup_loop(s); } static void coroutine_fn backup_pause(Job *job) diff --git a/block/block-copy.c b/block/block-copy.c index 27a5d1a41b2..a35fba45183 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -843,6 +843,47 @@ int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s, return ret; } +/* + * One scan step, like block_copy_reset_unallocated(); @cached_end + * tracks progress across calls, @count how far @offset should move. + */ +void coroutine_fn GRAPH_RDLOCK +block_copy_calculate_zero_bitmap(BlockCopyState *s, int64_t offset, + int64_t *cached_end, int64_t *count) +{ + int64_t dirty_offset, dirty_bytes, dirty_end; + bool found; + + /* CBW mutates copy_bitmap from its own AioContext meanwhile. */ + WITH_QEMU_LOCK_GUARD(&s->lock) { + found = bdrv_dirty_bitmap_next_dirty_area(s->copy_bitmap, offset, + s->len, INT64_MAX, + &dirty_offset, &dirty_bytes); + } + + if (!found) { + *count = s->len - offset; + return; + } + dirty_end = dirty_offset + dirty_bytes; + + if (*cached_end < dirty_end) { + int64_t clusters; + int64_t query_offset = MAX(dirty_offset, *cached_end); + int ret = block_copy_is_cluster_allocated(s, query_offset, &clusters); + + if (ret >= 0) { + *cached_end = query_offset + clusters * s->cluster_size; + } else { + /* Best-effort: leave this area unmarked; it copies as data. */ + *cached_end = dirty_end; + } + } + + /* 0 if the query above didn't yet reach dirty_end: try again next call. */ + *count = *cached_end >= dirty_end ? dirty_end - offset : 0; +} + /* * Decide how @task is copied: COPY_WRITE_ZEROES if it reads as zero. May * shrink @task. Returns false if @task is to be skipped (already ended, diff --git a/include/block/block-copy.h b/include/block/block-copy.h index 57e13f82f78..40dd5432735 100644 --- a/include/block/block-copy.h +++ b/include/block/block-copy.h @@ -43,6 +43,10 @@ void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes); int64_t coroutine_fn GRAPH_RDLOCK block_copy_reset_unallocated(BlockCopyState *s, int64_t offset, int64_t *count); +void coroutine_fn GRAPH_RDLOCK +block_copy_calculate_zero_bitmap(BlockCopyState *s, int64_t offset, + int64_t *cached_end, int64_t *count); + int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes, bool ignore_ratelimit, uint64_t timeout_ns, BlockCopyAsyncCallbackFunc cb, -- 2.53.0