From nobody Mon May 25 13:48:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1777309590; cv=none; d=zohomail.com; s=zohoarc; b=EFQJeiLQd9LQCLoFDklM0lAP2ElQ8RlQEs4VlfZcZy4M564A73/1lpCUYwYyhXz+yeyec9s6mN6wuaM9nyAbUmGnhJBCBdxEkDyAfOYPEwDVYuullM//PuQG9RmnlEFJ+RuhJFFwICHyHT5R+HIordPuo50hp77aK/hfm9uuOsA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777309590; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=RNf7Qtsfx36oLLaeD/N/V5PatsHP0UT/LP0p18adqyc=; b=WRuXcP7+F4trvvESd6YXbOIk+3L4uWzzIIQBRGgxh5RqJMG7YavPGD/uMYe43VrSo2EaxVbBaMVjBvxY4QPzAAzq09v/WUAlItveKSZhYwKiOQnJfmhn7H3f712NyzWK6ab0lR1sIzEOaXTH3j/aKJsyNVcDfRjJ9Z3SNEFiz94= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777309590617991.8278767562823; Mon, 27 Apr 2026 10:06:30 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wHPP4-0007Zm-Fp; Mon, 27 Apr 2026 13:05:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wHPP3-0007Yh-3m for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:49 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wHPP1-0006Rm-Mc for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:48 -0400 Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-339-xeNFhFwbOXqFn5IM-6mYQQ-1; Mon, 27 Apr 2026 13:05:43 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CF1251800609; Mon, 27 Apr 2026 17:05:41 +0000 (UTC) Received: from merkur.fritz.box (unknown [10.44.49.22]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 951A5180047F; Mon, 27 Apr 2026 17:05:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777309547; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=RNf7Qtsfx36oLLaeD/N/V5PatsHP0UT/LP0p18adqyc=; b=dyUA6vP5yOuy1t9xK/acm8c79iojvmzZQJeoKSuzR3r8x3t1B1l9Ws9wIFjUdtXzaE3LI1 CXmMVQ6aEYtyXSEi0aa+BF2bv+XboYLW8ByyBVOLuTMi9Hph9b712qVfW63L41zn0kJKgl TYkEEqL3EI2xqUTjTlOSYKHvMdMrJUo= X-MC-Unique: xeNFhFwbOXqFn5IM-6mYQQ-1 X-Mimecast-MFC-AGG-ID: xeNFhFwbOXqFn5IM-6mYQQ_1777309542 From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, den@openvz.org, stefanha@redhat.com, qemu-stable@nongnu.org, qemu-devel@nongnu.org Subject: [PATCH 1/4] commit: Drain nodes across all of bdrv_commit() Date: Mon, 27 Apr 2026 19:05:17 +0200 Message-ID: <20260427170520.101242-2-kwolf@redhat.com> In-Reply-To: <20260427170520.101242-1-kwolf@redhat.com> References: <20260427170520.101242-1-kwolf@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Received-SPF: pass (zohomail.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=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1777309593287154100 Content-Type: text/plain; charset="utf-8" The whole implementation of bdrv_commit() is only correct if no new writes come in while it's running: It has only a single loop checking the allocation status for each block and finally calls bdrv_make_empty() without checking if that throws away any new changes. We already have to drain while taking the graph write lock. Just extend the drained section to all of bdrv_commit() to make sure that we don't get any inconsistencies. Signed-off-by: Kevin Wolf Reviewed-by: Denis V. Lunev Tested-by: Denis V. Lunev --- block/commit.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/block/commit.c b/block/commit.c index 0d9e1a16d7a..c5e3ef03a21 100644 --- a/block/commit.c +++ b/block/commit.c @@ -518,6 +518,7 @@ int bdrv_commit(BlockDriverState *bs) if (!drv) return -ENOMEDIUM; =20 + bdrv_drain_all_begin(); bdrv_graph_rdlock_main_loop(); =20 backing_file_bs =3D bdrv_cow_bs(bs); @@ -549,6 +550,10 @@ int bdrv_commit(BlockDriverState *bs) BLK_PERM_ALL); backing =3D blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_AL= L); =20 + /* We drained all nodes, but still make requests through BlockBackends= */ + blk_set_disable_request_queuing(src, true); + blk_set_disable_request_queuing(backing, true); + ret =3D blk_insert_bs(src, bs, &local_err); if (ret < 0) { error_report_err(local_err); @@ -565,7 +570,7 @@ int bdrv_commit(BlockDriverState *bs) =20 bdrv_graph_rdunlock_main_loop(); =20 - bdrv_graph_wrlock_drained(); + bdrv_graph_wrlock(); bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort); bdrv_set_backing_hd(bs, commit_top_bs, &error_abort); bdrv_graph_wrunlock(); @@ -647,7 +652,7 @@ ro_cleanup: blk_unref(backing); =20 bdrv_graph_rdunlock_main_loop(); - bdrv_graph_wrlock_drained(); + bdrv_graph_wrlock(); if (bdrv_cow_bs(bs) !=3D backing_file_bs) { bdrv_set_backing_hd(bs, backing_file_bs, &error_abort); } @@ -663,6 +668,7 @@ ro_cleanup: =20 out: bdrv_graph_rdunlock_main_loop(); + bdrv_drain_all_end(); =20 return ret; } --=20 2.53.0 From nobody Mon May 25 13:48:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1777309569; cv=none; d=zohomail.com; s=zohoarc; b=kwUjn15lSA9tNJuqgSi4YM/Q+hGPpzqN/3K1YPuPFVLAp+aclNYuRR4DjTqdLsksrAXkrIMYQtuNBNo+uf/zDjAN+sVqSO3MtTTyVRIn1VmD7a3hDOEtIxuEHK21/MSGRfyyHQ70ENCBiaYQn6FmZ1O+ssSDbdyEktsKxe8PUFQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777309569; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=3kv75jBc4wfec0Dved34GH/yumDj1olUf9AKVp+bi4g=; b=ftR6orJ3w4SwcMVI3s7ZIpWur7SAB26Y31eb5nWwKQ4PYMl49s0PTKrdv3sBD3Jp8uui5Vhr0CnPIKPMZf22HwD05isZwxuUHHjC89aMC77ZZ5YHuIyep2nLNq0ezPqQAec/pzSH1MsKduaDJf2M8vJbxmgBoXK5Mdfjqw8emLc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777309569538571.1414448594156; Mon, 27 Apr 2026 10:06:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wHPP8-0007c7-0k; Mon, 27 Apr 2026 13:05:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wHPP5-0007af-H5 for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:51 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wHPP3-0006TS-OR for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:51 -0400 Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-148-euhHDi6PP8q6vcHVmnplng-1; Mon, 27 Apr 2026 13:05:45 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 65FF819560B0; Mon, 27 Apr 2026 17:05:44 +0000 (UTC) Received: from merkur.fritz.box (unknown [10.44.49.22]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 440F71800446; Mon, 27 Apr 2026 17:05:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777309549; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3kv75jBc4wfec0Dved34GH/yumDj1olUf9AKVp+bi4g=; b=A1e6yITKIB/c5C863dyjtv8M+654qKx5T3XXX4z6Uzf6mAMrWg9BBkeKa6QlqWLSSP6ec3 T3sKCbH4wffxATcewHjsUcWIMlqq556MdDMnBh3A1Kn7jnQ4Ltm/Z/WrN6WTy1pepWrJXU JH+y4bB0qFuJfb5ykSngyMm8Fp3hC0U= X-MC-Unique: euhHDi6PP8q6vcHVmnplng-1 X-Mimecast-MFC-AGG-ID: euhHDi6PP8q6vcHVmnplng_1777309544 From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, den@openvz.org, stefanha@redhat.com, qemu-stable@nongnu.org, qemu-devel@nongnu.org Subject: [PATCH 2/4] qemu-io: Add 'aio_discard' command Date: Mon, 27 Apr 2026 19:05:18 +0200 Message-ID: <20260427170520.101242-3-kwolf@redhat.com> In-Reply-To: <20260427170520.101242-1-kwolf@redhat.com> References: <20260427170520.101242-1-kwolf@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Received-SPF: pass (zohomail.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=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1777309573413154100 Content-Type: text/plain; charset="utf-8" Testing interactions between multiple requests that include discard requests require that qemu-io can do the discard asynchronously, like it already does for reads and writes. To this effect, add an 'aio_discard' command. Signed-off-by: Kevin Wolf Reviewed-by: Denis V. Lunev Tested-by: Denis V. Lunev --- qemu-io-cmds.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 13e03301624..0f5baa70f94 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -2218,6 +2218,118 @@ static int discard_f(BlockBackend *blk, int argc, c= har **argv) return 0; } =20 +static void aio_discard_help(void) +{ + printf( +"\n" +" asynchronously discards a range of bytes from the given offset\n" +"\n" +" Example:\n" +" 'aio_discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\= n" +"\n" +" Discards a segment of the currently open file.\n" +" -C, -- report statistics in a machine parsable format\n" +" -q, -- quiet mode, do not show I/O statistics\n" +" The discard is performed asynchronously and the aio_flush command must b= e\n" +" used to ensure all outstanding aio requests have been completed.\n" +" Note that due to its asynchronous nature, this command will be\n" +" considered successful once the request is submitted, independently\n" +" of potential I/O errors.\n" +"\n"); +} + +static int aio_discard_f(BlockBackend *blk, int argc, char **argv); + +static const cmdinfo_t aio_discard_cmd =3D { + .name =3D "aio_discard", + .cfunc =3D aio_discard_f, + .perm =3D BLK_PERM_WRITE, + .argmin =3D 2, + .argmax =3D -1, + .args =3D "[-Cq] off len", + .oneline =3D "asynchronously discards a number of bytes", + .help =3D aio_discard_help, +}; + +static void aio_discard_done(void *opaque, int ret) +{ + struct aio_ctx *ctx =3D opaque; + struct timespec t2; + + clock_gettime(CLOCK_MONOTONIC, &t2); + + if (ret < 0) { + printf("aio_discard failed: %s\n", strerror(-ret)); + block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); + goto out; + } + + block_acct_done(blk_get_stats(ctx->blk), &ctx->acct); + + if (ctx->qflag) { + goto out; + } + + /* Finally, report back -- -C gives a parsable format */ + t2 =3D tsub(t2, ctx->t1); + print_report("discarded ", &t2, ctx->offset, ctx->qiov.size, + ctx->qiov.size, 1, ctx->Cflag); +out: + g_free(ctx); +} + +static int aio_discard_f(BlockBackend *blk, int argc, char **argv) +{ + int c, ret; + int64_t count; + struct aio_ctx *ctx =3D g_new0(struct aio_ctx, 1); + + ctx->blk =3D blk; + + while ((c =3D getopt(argc, argv, "Cq")) !=3D -1) { + switch (c) { + case 'C': + ctx->Cflag =3D true; + break; + case 'q': + ctx->qflag =3D true; + break; + default: + qemuio_command_usage(&aio_discard_cmd); + return -EINVAL; + } + } + + if (optind !=3D argc - 2) { + qemuio_command_usage(&aio_discard_cmd); + return -EINVAL; + } + + ctx->offset =3D cvtnum(argv[optind]); + if (ctx->offset < 0) { + ret =3D ctx->offset; + print_cvtnum_err(ret, argv[optind]); + g_free(ctx); + return ret; + } + optind++; + + count =3D cvtnum(argv[optind]); + if (count < 0) { + print_cvtnum_err(count, argv[optind]); + g_free(ctx); + return count; + } + + clock_gettime(CLOCK_MONOTONIC, &ctx->t1); + ctx->qiov.size =3D count; + block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, + BLOCK_ACCT_UNMAP); + blk_aio_pdiscard(blk, ctx->offset, count, aio_discard_done, ctx); + + return 0; +} + static int alloc_f(BlockBackend *blk, int argc, char **argv) { BlockDriverState *bs =3D blk_bs(blk); @@ -2800,6 +2912,7 @@ static void __attribute((constructor)) init_qemuio_co= mmands(void) qemuio_add_command(&length_cmd); qemuio_add_command(&info_cmd); qemuio_add_command(&discard_cmd); + qemuio_add_command(&aio_discard_cmd); qemuio_add_command(&alloc_cmd); qemuio_add_command(&map_cmd); qemuio_add_command(&reopen_cmd); --=20 2.53.0 From nobody Mon May 25 13:48:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1777309585; cv=none; d=zohomail.com; s=zohoarc; b=S7w5NCon6XDzo1iN2U4xsK05jQpK4Kt9slxrIf48ThPnNdvysVW8LLVsQWAaXJ87x8bb4gAffnZ3khG4PGKJIkTJ+6OBkqhR1vutAPsoXqRV/P3yk3r+DAGhNUyYHeb+qw5YXrRP94fHzUlwJIeCyvqcDqLtSPClI1DNU9WnyPM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777309585; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=5mxm+H4XFJxx9sZcIhYP6Y+Z1xUv6tjNOfVcPbR28dE=; b=iFh0UjWz49ApNNL9AeywoKb7B6G/L26wwNNm+DBtd6wMTeSjBckDm7hs/6+yoOQ71+x/RPy6Bwg1ddyI6Bg8TKtMgluvqM0DAG5pFo/LLRSEsDIV6a42t0EGg4yKKI2wszT7mMNoan5LO+KT7ekq0lkh5EQHcIbHwe5UwtuXBZI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777309585853722.027017780236; Mon, 27 Apr 2026 10:06:25 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wHPPA-0007gX-8o; Mon, 27 Apr 2026 13:05:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wHPP8-0007cP-1x for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:54 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wHPP6-0006UG-6K for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:53 -0400 Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-575-0cdDGZf3NhCmrnpO8Hgv1w-1; Mon, 27 Apr 2026 13:05:48 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id DB3491956059; Mon, 27 Apr 2026 17:05:46 +0000 (UTC) Received: from merkur.fritz.box (unknown [10.44.49.22]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id CF451180047F; Mon, 27 Apr 2026 17:05:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777309551; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5mxm+H4XFJxx9sZcIhYP6Y+Z1xUv6tjNOfVcPbR28dE=; b=Koo6UR3+Q8J/5ZW6kch0iYA6ZkBQ84jgaAmQKCe1D14EoKEZpsMA4JnzMNxQxj8H2NjGaZ XUvDFrPzwfIA9DnUv1pm/42/F+3ATyjdjAPWPyarsDwAqC9BumuXgVWfvYgxeRTo7w/qkg DJ9NG8zVMeeq3ZlefUEYu9LnPxSG2yE= X-MC-Unique: 0cdDGZf3NhCmrnpO8Hgv1w-1 X-Mimecast-MFC-AGG-ID: 0cdDGZf3NhCmrnpO8Hgv1w_1777309547 From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, den@openvz.org, stefanha@redhat.com, qemu-stable@nongnu.org, qemu-devel@nongnu.org Subject: [PATCH 3/4] qcow2: Fix corruption on discard during write with COW Date: Mon, 27 Apr 2026 19:05:19 +0200 Message-ID: <20260427170520.101242-4-kwolf@redhat.com> In-Reply-To: <20260427170520.101242-1-kwolf@redhat.com> References: <20260427170520.101242-1-kwolf@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Received-SPF: pass (zohomail.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=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1777309586997158500 Content-Type: text/plain; charset="utf-8" Most code in qcow2 that accesses (and potentially modifies) L2 tables does so while holding s->lock. There is one exception, which is allocating writes. They hold the lock initially while allocating clusters, but drop it for writing the guest payload before taking the lock again for updating the L2 tables. This allows concurrent requests that touch other parts of the image file to continue in parallel and is an important performance optimisation. However, this means that other requests that run while the lock is dropped for writing guest data must synchronise with the list of allocating requests in s->cluster_allocs and wait if they would overlap. For writes, this is done in handle_dependencies(), but discard and write zeros operations neglect to synchronise with s->cluster_allocs. This means that discard can free a cluster whose L2 entry will already be modified in qcow2_alloc_cluster_link_l2() by a previously started write. In the case of a pre-allocated zero cluster that is in the process of being overwritten, this means that discard can lead to a situation where the cluster is still mapped (because the write will restore the L2 entry just without the zero flag), but its refcount has been decreased, resulting in a corrupted image. Add the missing synchronisation to qcow2_cluster_discard() and qcow2_subcluster_zeroize() to fix the problem. Cc: qemu-stable@nongnu.org Reported-by: Denis V. Lunev Signed-off-by: Kevin Wolf Reviewed-by: Denis V. Lunev Tested-by: Denis V. Lunev --- block/qcow2-cluster.c | 52 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index c655bf6df42..8b1e80bd0b3 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1392,6 +1392,9 @@ count_single_write_clusters(BlockDriverState *bs, int= nb_clusters, * the same cluster. In this case we need to wait until the previous * request has completed and updated the L2 table accordingly. * + * If allow_shortening =3D=3D true, instead of waiting for a dependency, *= cur_bytes + * can be shortened so that the cluster allocations don't overlap. + * * Returns: * 0 if there was no dependency. *cur_bytes indicates the number of * bytes from guest_offset that can be read before the next @@ -1403,7 +1406,9 @@ count_single_write_clusters(BlockDriverState *bs, int= nb_clusters, */ static int coroutine_fn handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, - uint64_t *cur_bytes, QCowL2Met= a **m) + uint64_t *cur_bytes, + bool allow_shortening, + QCowL2Meta **m) { BDRVQcow2State *s =3D bs->opaque; QCowL2Meta *old_alloc; @@ -1434,7 +1439,7 @@ static int coroutine_fn handle_dependencies(BlockDriv= erState *bs, =20 /* Conflict */ =20 - if (start < old_start) { + if (start < old_start && allow_shortening) { /* Stop at the start of a running allocation */ bytes =3D old_start - start; } else { @@ -1469,6 +1474,29 @@ static int coroutine_fn handle_dependencies(BlockDri= verState *bs, return 0; } =20 +static void coroutine_mixed_fn wait_for_dependencies(BlockDriverState *bs, + uint64_t guest_offset, + uint64_t bytes) +{ + BDRVQcow2State *s =3D bs->opaque; + QCowL2Meta *m =3D NULL; + int ret; + + /* + * Discard has some non-coroutine callers (creating internal snapshots= and + * make empty). They are calling from qemu-img or in a drained section= , so + * we know that no writes can be in progress. + */ + if (!qemu_in_coroutine()) { + assert(QLIST_EMPTY(&s->cluster_allocs)); + return; + } + + do { + ret =3D handle_dependencies(bs, guest_offset, &bytes, false, &m); + } while (ret =3D=3D -EAGAIN); +} + /* * Checks how many already allocated clusters that don't require a new * allocation there are at the given guest_offset (up to *bytes). @@ -1840,7 +1868,7 @@ again: * the right synchronisation between the in-flight request= and * the new one. */ - ret =3D handle_dependencies(bs, start, &cur_bytes, m); + ret =3D handle_dependencies(bs, start, &cur_bytes, true, m); if (ret =3D=3D -EAGAIN) { /* Currently handle_dependencies() doesn't yield if we already= had * an allocation. If it did, we would have to clean up the L2M= eta @@ -2000,6 +2028,15 @@ int qcow2_cluster_discard(BlockDriverState *bs, uint= 64_t offset, int64_t cleared; int ret; =20 + /* + * If we're touching a cluster for which allocating writes are in flig= ht, + * wait for them to complete to avoid conflicting metadata updates. + * + * We don't need to allocate a QCowL2Meta for the discard operation be= cause + * s->lock is held for the duration of the whole operation. + */ + wait_for_dependencies(bs, offset, bytes); + /* Caller must pass aligned values, except at image end */ assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) || @@ -2160,6 +2197,15 @@ int coroutine_fn qcow2_subcluster_zeroize(BlockDrive= rState *bs, uint64_t offset, int64_t cleared; int ret; =20 + /* + * If we're touching a cluster for which allocating writes are in flig= ht, + * wait for them to complete to avoid conflicting metadata updates. + * + * We don't need to allocate a QCowL2Meta for the zeroize operation be= cause + * s->lock is held for the duration of the whole operation. + */ + wait_for_dependencies(bs, offset, bytes); + /* If we have to stay in sync with an external data file, zero out * s->data_file first. */ if (data_file_is_raw(bs)) { --=20 2.53.0 From nobody Mon May 25 13:48:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1777309602; cv=none; d=zohomail.com; s=zohoarc; b=UBWgyIoaW98WWxiFb337fhOSuKErYm3kztphwXoTJtLqrk/HOC7fthvpo4RlsD64qw36FTYx+xNgbEHiHC0rr6gAAA8OMRfnR+qRqTnUFUdXh9VnP+u6CAkrfvzKa9OSpqLSbhY++COLnU197Yn1pqHhQc8Kqyo8UEXn2KouWpE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777309602; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=xt1Ev/wLan3HxX+yy3/W3SrxiXPBZBxO+DaqEQ//04c=; b=JD0CAXPtyhNF5egK+WEH/ETsN/zuOVHsqGPRL2rKUOkMIJrNql+149MX4SGbomAznjy3/Lb7XaOiS1yczHv9u7W0WlZqHmSQcxn1CnuOEyZqy58Hvck5pZSVhG1zqS52+q8XyXZ5WN3MOe7Lac3xJ3lxBVAl2umQhPJoB8iYWFc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777309602803348.61715159398454; Mon, 27 Apr 2026 10:06:42 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wHPPF-0007qG-V8; Mon, 27 Apr 2026 13:06:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wHPPA-0007j4-KK for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:58 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wHPP8-0006Ud-8g for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:55 -0400 Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-653-IC3RRJevMQyC33fVLEPCjw-1; Mon, 27 Apr 2026 13:05:50 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5C1C919560B4; Mon, 27 Apr 2026 17:05:49 +0000 (UTC) Received: from merkur.fritz.box (unknown [10.44.49.22]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4FE121800446; Mon, 27 Apr 2026 17:05:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777309553; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xt1Ev/wLan3HxX+yy3/W3SrxiXPBZBxO+DaqEQ//04c=; b=FRO0mJvj0nXivpU+I9K5yx16vr/Wk6M7gYG79LbBwzK/vNTJmu/+ch7UM4N+lvKHw79nvD mUFp5UR2wlmQvggDsnwF3os5cFXCKUm8T2XPnSVK9swGAY9NLtv3gNX61kdHr2Ekg1DSaI BBPBO6wx6oXu9MSSL0GiX0/UsJ+lDrY= X-MC-Unique: IC3RRJevMQyC33fVLEPCjw-1 X-Mimecast-MFC-AGG-ID: IC3RRJevMQyC33fVLEPCjw_1777309549 From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, den@openvz.org, stefanha@redhat.com, qemu-stable@nongnu.org, qemu-devel@nongnu.org Subject: [PATCH 4/4] iotests/046: Test that discard/write_zeroes wait for dependencies Date: Mon, 27 Apr 2026 19:05:20 +0200 Message-ID: <20260427170520.101242-5-kwolf@redhat.com> In-Reply-To: <20260427170520.101242-1-kwolf@redhat.com> References: <20260427170520.101242-1-kwolf@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Received-SPF: pass (zohomail.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=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1777309605406154100 Content-Type: text/plain; charset="utf-8" This is a regression test for the bug fixed in the previous commit where discard and write_zeroes operations wouldn't consider their dependencies in s->cluster_allocs. Without the fix, this results in a corrupted image. Signed-off-by: Kevin Wolf Reviewed-by: Denis V. Lunev Tested-by: Denis V. Lunev --- tests/qemu-iotests/046 | 46 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/046.out | 36 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046 index 4c9ed4d26e1..e03dd401479 100755 --- a/tests/qemu-iotests/046 +++ b/tests/qemu-iotests/046 @@ -184,6 +184,48 @@ aio_write -P 160 0x104000 0x18000 resume A aio_flush EOF + +# Create a pre-allocated zero cluster, then start a write on it and discar= d it +# before the L2 update is made +cat <