From patchwork Mon Mar 14 16:27:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanna Czenczek X-Patchwork-Id: 12780391 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 87A59C433F5 for ; Mon, 14 Mar 2022 16:34:43 +0000 (UTC) Received: from localhost ([::1]:43046 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nTnec-0003YL-EZ for qemu-devel@archiver.kernel.org; Mon, 14 Mar 2022 12:34:42 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53888) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nTnXc-0001Pm-9D for qemu-devel@nongnu.org; Mon, 14 Mar 2022 12:27:28 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:47400) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nTnXa-0005l7-N2 for qemu-devel@nongnu.org; Mon, 14 Mar 2022 12:27:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647275246; 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=uu5wEasI+3ljpLl6z5hpzxYb/IK7YQF8kQRvZ3I7iS4=; b=BnUI0FF05DFWAVrjMe0tLecj3MDCdUyv3v96S3Wr6qIe+PywqfKzw1VlMfC6QPqCdjDNet rSCiPlIpvxQ4JVGWJD09qZxEPqPb8RmBfapUfgk1pxtL9W1bFZsdopprdPpN9x96JjJXnV lVUAExLss5WBcpeuYdkhpg3B5LoESds= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-601-MnCnUHHfMLWjeac0yw7IQA-1; Mon, 14 Mar 2022 12:27:23 -0400 X-MC-Unique: MnCnUHHfMLWjeac0yw7IQA-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 9973A2999B2A; Mon, 14 Mar 2022 16:27:22 +0000 (UTC) Received: from localhost (unknown [10.39.194.97]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 55E5A2D460; Mon, 14 Mar 2022 16:27:22 +0000 (UTC) From: Hanna Reitz To: qemu-block@nongnu.org Subject: [PATCH for-7.0 1/2] block/vmdk: Fix reopening bs->file Date: Mon, 14 Mar 2022 17:27:18 +0100 Message-Id: <20220314162719.65384-2-hreitz@redhat.com> In-Reply-To: <20220314162719.65384-1-hreitz@redhat.com> References: <20220314162719.65384-1-hreitz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=hreitz@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=170.10.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Hanna Reitz , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" VMDK disk data is stored in extents, which may or may not be separate from bs->file. VmdkExtent.file points to where they are stored. Each that is stored in bs->file will simply reuse the exact pointer value of bs->file. (That is why vmdk_free_extents() will unref VmdkExtent.file (e->file) only if e->file != bs->file.) Reopen operations can change bs->file (they will replace the whole BdrvChild object, not just the BDS stored in that BdrvChild), and then we will need to change all .file pointers of all such VmdkExtents to point to the new BdrvChild. In vmdk_reopen_prepare(), we have to check which VmdkExtents are affected, and in vmdk_reopen_commit(), we can modify them. We have to split this because: - The new BdrvChild is created only after prepare, so we can change VmdkExtent.file only in commit - In commit, there no longer is any (valid) reference to the old BdrvChild object, so there would be nothing to compare VmdkExtent.file against to see whether it was equal to bs->file before reopening (There is BDRVReopenState.old_file_bs, but the old bs->file BdrvChild's .bs pointer will be NULL-ed when the new BdrvChild is created, and so we cannot compare VmdkExtent.file->bs against BDRVReopenState.old_file_bs) Signed-off-by: Hanna Reitz --- block/vmdk.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/block/vmdk.c b/block/vmdk.c index 37c0946066..38e5ab3806 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -178,6 +178,10 @@ typedef struct BDRVVmdkState { char *create_type; } BDRVVmdkState; +typedef struct BDRVVmdkReopenState { + bool *extents_using_bs_file; +} BDRVVmdkReopenState; + typedef struct VmdkMetaData { unsigned int l1_index; unsigned int l2_index; @@ -400,15 +404,63 @@ static int vmdk_is_cid_valid(BlockDriverState *bs) return 1; } -/* We have nothing to do for VMDK reopen, stubs just return success */ static int vmdk_reopen_prepare(BDRVReopenState *state, BlockReopenQueue *queue, Error **errp) { + BDRVVmdkState *s; + BDRVVmdkReopenState *rs; + int i; + assert(state != NULL); assert(state->bs != NULL); + assert(state->opaque == NULL); + + s = state->bs->opaque; + + rs = g_new0(BDRVVmdkReopenState, 1); + state->opaque = rs; + + /* + * Check whether there are any extents stored in bs->file; if bs->file + * changes, we will need to update their .file pointers to follow suit + */ + rs->extents_using_bs_file = g_new(bool, s->num_extents); + for (i = 0; i < s->num_extents; i++) { + rs->extents_using_bs_file[i] = s->extents[i].file == state->bs->file; + } + return 0; } +static void vmdk_reopen_clean(BDRVReopenState *state) +{ + BDRVVmdkReopenState *rs = state->opaque; + + g_free(rs->extents_using_bs_file); + g_free(rs); + state->opaque = NULL; +} + +static void vmdk_reopen_commit(BDRVReopenState *state) +{ + BDRVVmdkState *s = state->bs->opaque; + BDRVVmdkReopenState *rs = state->opaque; + int i; + + for (i = 0; i < s->num_extents; i++) { + if (rs->extents_using_bs_file[i]) { + s->extents[i].file = state->bs->file; + } + } + + vmdk_reopen_clean(state); +} + +static void vmdk_reopen_abort(BDRVReopenState *state) +{ + vmdk_reopen_clean(state); +} + static int vmdk_parent_open(BlockDriverState *bs) { char *p_name; @@ -3072,6 +3124,8 @@ static BlockDriver bdrv_vmdk = { .bdrv_open = vmdk_open, .bdrv_co_check = vmdk_co_check, .bdrv_reopen_prepare = vmdk_reopen_prepare, + .bdrv_reopen_commit = vmdk_reopen_commit, + .bdrv_reopen_abort = vmdk_reopen_abort, .bdrv_child_perm = bdrv_default_perms, .bdrv_co_preadv = vmdk_co_preadv, .bdrv_co_pwritev = vmdk_co_pwritev, From patchwork Mon Mar 14 16:27:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanna Czenczek X-Patchwork-Id: 12780374 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C2E3BC433F5 for ; Mon, 14 Mar 2022 16:32:38 +0000 (UTC) Received: from localhost ([::1]:38594 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nTncb-0000Xb-Lg for qemu-devel@archiver.kernel.org; Mon, 14 Mar 2022 12:32:37 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53912) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nTnXf-0001YD-Gd for qemu-devel@nongnu.org; Mon, 14 Mar 2022 12:27:31 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:45197) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nTnXd-0005lT-IX for qemu-devel@nongnu.org; Mon, 14 Mar 2022 12:27:31 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647275248; 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=1R9g94+vMC65XZjqr2KtePUIB0UeFoJjSaSLqLU9Teg=; b=QC1K2ZGZ8kGKYYR78fjj6/yllyEumohEAZXaXhx8i/IYwBLSglB/Zag+9zS7gL1Gxxcegh vC9CYQevektm3ncu0aJBft2dlQ7oo8p/dxAHvfErEmQB/9SLgJi7qFK+rEFVI9oi7kK3zS Dd98pPLAM7E79EM0PiZbptQCffqNUSs= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-6-jqjEgSZxNCaHVl3fAQn3VQ-1; Mon, 14 Mar 2022 12:27:24 -0400 X-MC-Unique: jqjEgSZxNCaHVl3fAQn3VQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3C613801585; Mon, 14 Mar 2022 16:27:24 +0000 (UTC) Received: from localhost (unknown [10.39.194.97]) by smtp.corp.redhat.com (Postfix) with ESMTPS id EB7102023A09; Mon, 14 Mar 2022 16:27:23 +0000 (UTC) From: Hanna Reitz To: qemu-block@nongnu.org Subject: [PATCH for-7.0 2/2] iotests/reopen-file: Test reopening file child Date: Mon, 14 Mar 2022 17:27:19 +0100 Message-Id: <20220314162719.65384-3-hreitz@redhat.com> In-Reply-To: <20220314162719.65384-1-hreitz@redhat.com> References: <20220314162719.65384-1-hreitz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=hreitz@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=170.10.133.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, 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_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Hanna Reitz , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This should work for all format drivers that support reopening, so test it. (This serves as a regression test for HEAD^: This test used to fail for VMDK before HEAD^.) Signed-off-by: Hanna Reitz --- tests/qemu-iotests/tests/reopen-file | 88 ++++++++++++++++++++++++ tests/qemu-iotests/tests/reopen-file.out | 5 ++ 2 files changed, 93 insertions(+) create mode 100755 tests/qemu-iotests/tests/reopen-file create mode 100644 tests/qemu-iotests/tests/reopen-file.out diff --git a/tests/qemu-iotests/tests/reopen-file b/tests/qemu-iotests/tests/reopen-file new file mode 100755 index 0000000000..24fd648050 --- /dev/null +++ b/tests/qemu-iotests/tests/reopen-file @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# group: rw quick +# +# Test reopening a format driver's file child +# +# Copyright (C) 2022 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import iotests +from iotests import imgfmt, qemu_img_create, QMPTestCase + + +image_size = 1 * 1024 * 1024 +test_img = os.path.join(iotests.test_dir, 'test.img') + + +class TestReopenFile(QMPTestCase): + def setUp(self) -> None: + assert qemu_img_create('-f', imgfmt, test_img, str(image_size)) == 0 + + # Add format driver node ('format') on top of the file ('file'), then + # add another raw node ('raw') on top of 'file' so for the reopen we + # can just switch from 'file' to 'raw' + self.vm = iotests.VM() + self.vm.add_blockdev(self.vm.qmp_to_opts({ + 'driver': imgfmt, + 'node-name': 'format', + 'file': { + 'driver': 'file', + 'node-name': 'file', + 'filename': test_img + } + })) + self.vm.add_blockdev(self.vm.qmp_to_opts({ + 'driver': 'raw', + 'node-name': 'raw', + 'file': 'file' + })) + self.vm.launch() + + def tearDown(self) -> None: + self.vm.shutdown() + os.remove(test_img) + + # Check if there was any qemu-io run that failed + if 'Pattern verification failed' in self.vm.get_log(): + print('ERROR: Pattern verification failed:') + print(self.vm.get_log()) + self.fail('qemu-io pattern verification failed') + + def test_reopen_file(self) -> None: + result = self.vm.qmp('blockdev-reopen', options=[{ + 'driver': imgfmt, + 'node-name': 'format', + 'file': 'raw' + }]) + self.assert_qmp(result, 'return', {}) + + # Do some I/O to the image to see whether it still works + # (Pattern verification will be checked by tearDown()) + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io format "write -P 42 0 64k"') + self.assert_qmp(result, 'return', '') + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io format "read -P 42 0 64k"') + self.assert_qmp(result, 'return', '') + + +if __name__ == '__main__': + # Must support creating images and reopen + iotests.main(supported_fmts=['qcow', 'qcow2', 'qed', 'raw', 'vdi', 'vhdx', + 'vmdk', 'vpc'], + supported_protocols=['file']) diff --git a/tests/qemu-iotests/tests/reopen-file.out b/tests/qemu-iotests/tests/reopen-file.out new file mode 100644 index 0000000000..ae1213e6f8 --- /dev/null +++ b/tests/qemu-iotests/tests/reopen-file.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK