From nobody Mon Feb 9 11:33:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; 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=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1613679769; cv=none; d=zohomail.com; s=zohoarc; b=oCEknbmWtOWBoWSUWmK4zWdXN6H9qLV/DgVlkxCwcl0kku26zjrXJrjgli5BWOpIDmkwiYQpT3LimOqTlDPiBym5BnULgq28FZRCOTFxeGv0L6rTsGw3okSZ0/bU/jlmvSyQ2CmYFPtoPs1fJaQCBzHDh42end5od27GABWcv9o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1613679769; h=Content-Type: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=oCOEY2aazGCOIFvFQIRJGGlpCSBGnj3Ux92aLuQ3nr0=; b=MZHxF+feWpoWzR+Jn/ofke80faL8VYkxGLHyEWQKtSNHKykKE5QkvKKbp0gm0GqR9Ry0qQvlbO/LB7ICHnXNfVxCsvFesnICoi4ZviuDIcvJLgGBO53CP5eVul43r4b/7u/Og3mhEjXA8KXldeRm1W3B14UCKtBcTLtuNQ134ds= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; 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=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 1613679768600748.625141497251; Thu, 18 Feb 2021 12:22:48 -0800 (PST) Received: from localhost ([::1]:55742 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lCpp1-0002JU-Gs for importer@patchew.org; Thu, 18 Feb 2021 15:22:47 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46300) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lCpiP-0005Kd-Bt for qemu-devel@nongnu.org; Thu, 18 Feb 2021 15:16:02 -0500 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:58594) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1lCpiD-0000Iw-F9 for qemu-devel@nongnu.org; Thu, 18 Feb 2021 15:15:55 -0500 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-222-AoDuBSwhMnu8XdtqFE8cMw-1; Thu, 18 Feb 2021 15:15:43 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1D103427C1; Thu, 18 Feb 2021 20:15:42 +0000 (UTC) Received: from blue.redhat.com (ovpn-113-156.phx2.redhat.com [10.3.113.156]) by smtp.corp.redhat.com (Postfix) with ESMTP id D0D045B4B0; Thu, 18 Feb 2021 20:15:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1613679344; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=oCOEY2aazGCOIFvFQIRJGGlpCSBGnj3Ux92aLuQ3nr0=; b=BM1h4rIfghQNfhjB4bUyFtXz9QVeTZC8eOoNeJIxaW8Pyuk1Xx+TqWMvU0O73tjz4v+V9f 0GINFRsuucvIaMbiNWDtKp9kFOasMv6xHPieO2lsC1F9Fpllpp4p6a5d2HwhMejr96hpep zKZh74yup6Ct563Bo6EmG15Gw5qIQ+s= X-MC-Unique: AoDuBSwhMnu8XdtqFE8cMw-1 From: Eric Blake To: qemu-devel@nongnu.org Subject: [PATCH 4/5] nbd/server: Avoid unaligned dirty-bitmap status Date: Thu, 18 Feb 2021 14:15:27 -0600 Message-Id: <20210218201528.127099-5-eblake@redhat.com> In-Reply-To: <20210218201528.127099-1-eblake@redhat.com> References: <20210218201528.127099-1-eblake@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=eblake@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable 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=lists.gnu.org; Received-SPF: pass client-ip=63.128.21.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 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_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , vsementsov@virtuozzo.com, qemu-block@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The NBD spec requires that responses to NBD_CMD_BLOCK_STATUS be aligned to the server's advertised min_block alignment, if the client agreed to abide by alignments. In general, since dirty bitmap granularity cannot go below 512, and it is hard to provoke qcow2 to go above an alignment of 512, this is not an issue. But now that the block layer can see through filters, it is possible to use blkdebug to show a scenario where where the server is provoked into supplying a non-compliant reply, as show in iotest 241. Thus, it is time to fix the dirty bitmap code to round requests to aligned boundaries. Signed-off-by: Eric Blake --- nbd/server.c | 30 ++++++++++++++++++++++++++---- tests/qemu-iotests/241 | 5 ++--- tests/qemu-iotests/241.out | 2 +- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 40847276ca64..31462abaee63 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2020 Red Hat, Inc. + * Copyright (C) 2016-2021 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device Server Side @@ -2175,7 +2175,8 @@ static int nbd_co_send_block_status(NBDClient *client= , uint64_t handle, } /* Populate @ea from a dirty bitmap. */ -static void bitmap_to_extents(BdrvDirtyBitmap *bitmap, +static void bitmap_to_extents(uint32_t align, + BdrvDirtyBitmap *bitmap, uint64_t offset, uint64_t length, NBDExtentArray *es) { @@ -2186,10 +2187,23 @@ static void bitmap_to_extents(BdrvDirtyBitmap *bitm= ap, bdrv_dirty_bitmap_lock(bitmap); for (start =3D offset; - bdrv_dirty_bitmap_next_dirty_area(bitmap, start, end, INT32_MAX, + bdrv_dirty_bitmap_next_dirty_area(bitmap, start, end, + INT32_MAX - align + 1, &dirty_start, &dirty_count); start =3D dirty_start + dirty_count) { + /* + * Round unaligned bits: any transition mid-alignment makes + * that entire aligned region appear dirty. + */ + assert(QEMU_IS_ALIGNED(start, align)); + if (!QEMU_IS_ALIGNED(dirty_start, align)) { + dirty_count +=3D dirty_start - QEMU_ALIGN_DOWN(dirty_start, al= ign); + dirty_start =3D QEMU_ALIGN_DOWN(dirty_start, align); + } + if (!QEMU_IS_ALIGNED(dirty_count, align)) { + dirty_count =3D QEMU_ALIGN_UP(dirty_count, align); + } if ((nbd_extent_array_add(es, dirty_start - start, 0) < 0) || (nbd_extent_array_add(es, dirty_count, NBD_STATE_DIRTY) < 0)) { @@ -2214,7 +2228,15 @@ static int nbd_co_send_bitmap(NBDClient *client, uin= t64_t handle, unsigned int nb_extents =3D dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_E= XTENTS; g_autoptr(NBDExtentArray) ea =3D nbd_extent_array_new(nb_extents); - bitmap_to_extents(bitmap, offset, length, ea); + /* Easiest to just refuse to answer an unaligned query */ + if (client->check_align && + !QEMU_IS_ALIGNED(offset | length, client->check_align)) { + return nbd_co_send_structured_error(client, handle, -EINVAL, + "unaligned dirty bitmap reques= t", + errp); + } + + bitmap_to_extents(client->check_align ?: 1, bitmap, offset, length, ea= ); return nbd_co_send_extents(client, handle, ea, last, context_id, errp); } diff --git a/tests/qemu-iotests/241 b/tests/qemu-iotests/241 index 49e2bc09e5bc..b4d2e1934d66 100755 --- a/tests/qemu-iotests/241 +++ b/tests/qemu-iotests/241 @@ -124,9 +124,8 @@ nbd_server_start_unix_socket -B b0 -A --image-opts \ TEST_IMG=3D"driver=3Dnbd,server.type=3Dunix,server.path=3D$nbd_unix_socket" $QEMU_NBD_PROG --list -k $nbd_unix_socket | grep '\(size\|min\)' -# FIXME: this should report a single 4k block of "data":false which transl= ates -# to the dirty bitmap being set for at least part of the region; "data":tr= ue -# is wrong unless the entire 4k is clean. +# Reports a single 4k block of "data":false, meaning dirty. Reporting +# "data":true would be wrong (the entire region is not clean). $QEMU_IMG map --output=3Djson --image-opts \ "$TEST_IMG",x-dirty-bitmap=3Dqemu:dirty-bitmap:b0 | _filter_qemu_img_map # Reports a single 4k block of "zero":true,"data":true, meaning allocated diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out index 12a899ba9181..2368b71054d3 100644 --- a/tests/qemu-iotests/241.out +++ b/tests/qemu-iotests/241.out @@ -43,6 +43,6 @@ wrote 512/512 bytes at offset 512 Formatting 'TEST_DIR/t.IMGFMT.qcow2', fmt=3Dqcow2 size=3D4096 backing_file= =3DTEST_DIR/t.IMGFMT.mid backing_fmt=3Dqcow2 size: 4096 min block: 4096 -[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "o= ffset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": false}] [{ "start": 0, "length": 4096, "depth": 0, "zero": true, "data": true, "of= fset": OFFSET}] *** done --=20 2.30.1