From nobody Sat Apr 27 21:47:10 2024 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1669645061; cv=none; d=zohomail.com; s=zohoarc; b=Lv29yLtofYzh2c6B5QFdqD+domyEDDOM8TcLT9r+SLh+g2xwIKlA1/CTZKBp9+sQzluHjlvGtIaulm6BrXULUN3tYDrPZj0gAwT/iF1fT2QPPvxt8ZG8J43CHdlIe6g2f//ZkGAiCeVz/yr/lvdJy6jQXuRNNcXlc+HJvzgAkRg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1669645061; h=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=r8BwCjwIv56ryutNz6xJ/e48LVbcViq+vpSmW1/ifRI=; b=jHs62nZ8M95S7ugtcWOFiB8t9Yq4EZBN1FMf/PPiaPrlOcmybABhgYFH8FSqlghaKkbt6KAcdH3zrQEss1UTLTXNzhDc69OSGuQr+ZAymp+IUMw3zp8zfSZPxEGy/TkkQrdVatN87OGbZ+pm0+/agNXker3B1z6chWGNBj9i1Mc= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1669645061120458.64436749758283; Mon, 28 Nov 2022 06:17:41 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ozew9-0008Nv-4w; Mon, 28 Nov 2022 09:16:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ozevY-0008EQ-SH for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:12 -0500 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 1ozevW-0005SN-Iq for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:07 -0500 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-490-l9YqmRm0MYuYH6b3mID9qw-1; Mon, 28 Nov 2022 09:15:58 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 408BF3C3C130; Mon, 28 Nov 2022 14:15:19 +0000 (UTC) Received: from loop.redhat.com (unknown [10.35.206.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 522362166B4B; Mon, 28 Nov 2022 14:15:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1669644961; 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=r8BwCjwIv56ryutNz6xJ/e48LVbcViq+vpSmW1/ifRI=; b=ga0gChLt2UJiOLcsVJ23x2a+S74s5xZlM7cHvP/85Mz1nofHBROU0r4t29Ym2RvlMh/z7b z1vug+2+QthzBhiU3MNx3qKiX91wiADpgNQqbe93bAVrNbcsptrZlpVaY1bAcFuqJLv6Rt WR1l8JOx35kYqv1ns6UHUsz1MIvdQpw= X-MC-Unique: l9YqmRm0MYuYH6b3mID9qw-1 From: Nir Soffer To: qemu-devel@nongnu.org Cc: Thomas Huth , Paolo Bonzini , Kevin Wolf , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , qemu-block@nongnu.org, =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Hanna Reitz , Nir Soffer Subject: [PATCH v2 1/5] qemu-img.c: Move IO_BUF_SIZE to the top of the file Date: Mon, 28 Nov 2022 16:15:10 +0200 Message-Id: <20221128141514.388724-2-nsoffer@redhat.com> In-Reply-To: <20221128141514.388724-1-nsoffer@redhat.com> References: <20221128141514.388724-1-nsoffer@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 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=170.10.133.124; envelope-from=nsoffer@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_H2=-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.29 Precedence: list List-Id: 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: 1669645161924100001 Content-Type: text/plain; charset="utf-8" This macro is used by various commands (compare, convert, rebase) but it is defined somewhere in the middle of the file. I'm going to use it in the new checksum command so lets clean up a bit before that. Reviewed-by: Hanna Reitz --- qemu-img.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index a9b3a8103c..c03d6b4b31 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -49,20 +49,21 @@ #include "block/block_int.h" #include "block/blockjob.h" #include "block/qapi.h" #include "crypto/init.h" #include "trace/control.h" #include "qemu/throttle.h" #include "block/throttle-groups.h" =20 #define QEMU_IMG_VERSION "qemu-img version " QEMU_FULL_VERSION \ "\n" QEMU_COPYRIGHT "\n" +#define IO_BUF_SIZE (2 * MiB) =20 typedef struct img_cmd_t { const char *name; int (*handler)(int argc, char **argv); } img_cmd_t; =20 enum { OPTION_OUTPUT =3D 256, OPTION_BACKING_CHAIN =3D 257, OPTION_OBJECT =3D 258, @@ -1281,22 +1282,20 @@ static int compare_buffers(const uint8_t *buf1, con= st uint8_t *buf2, if (!!memcmp(buf1 + i, buf2 + i, len) !=3D res) { break; } i +=3D len; } =20 *pnum =3D i; return res; } =20 -#define IO_BUF_SIZE (2 * MiB) - /* * Check if passed sectors are empty (not allocated or contain only 0 byte= s) * * Intended for use by 'qemu-img compare': Returns 0 in case sectors are * filled with 0, 1 if sectors contain non-zero data (this is a comparison * failure), and 4 on error (the exit status for read errors), after emitt= ing * an error message. * * @param blk: BlockBackend for the image * @param offset: Starting offset to check --=20 2.38.1 From nobody Sat Apr 27 21:47:10 2024 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1669645060; cv=none; d=zohomail.com; s=zohoarc; b=Cghd+UmW67prwnjx/AkPZfvbtO7koklrrTwxX+DLEK98X3RF2O0Vcmr6wMZctHp2x+Mxauph/QD4EM2NeqZ3b0/EgiKJIzHmZf7GXxwAydW+ZBzQezXLc1zEBPfvvkrzc3U2HzjUZhQLesQ9ZDslXMQWqzic2br3Smb8q+lVtzQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1669645060; h=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=ad/8cwhve4H+k8AjNmhbKjCGzt+BN5Wcq1f4Dpmtydk=; b=gRhKMoHLM21KxmKcdiLro9qu2zgrmasnmADssfuctpfJqlGvnrG3lDUJ0cr3S1dfZpbqgbFTdlbhxeiPkh2fF1IZbTsUD4GXgCr5k8oJwZ48KOt1s57QeWr0D8M671JJmCzVFf7/UvnWS9dsh+CMSIuJ2YntkmBPAjtBueA2o+A= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1669645060635774.7036338189457; Mon, 28 Nov 2022 06:17:40 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ozew8-0008Ns-Sq; Mon, 28 Nov 2022 09:16:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ozevV-0008D3-G3 for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:10 -0500 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 1ozevT-0005SY-61 for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:04 -0500 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-618-jm_o4ewrOs-JZ9S_TBMGTQ-1; Mon, 28 Nov 2022 09:16:00 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 773833C3D279; Mon, 28 Nov 2022 14:15:21 +0000 (UTC) Received: from loop.redhat.com (unknown [10.35.206.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8B4462166B4D; Mon, 28 Nov 2022 14:15:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1669644961; 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=ad/8cwhve4H+k8AjNmhbKjCGzt+BN5Wcq1f4Dpmtydk=; b=hUIno7zLRkf/k44S1t9K2oHzzXNpQNfLrMN6ToXQhDGcDF2UWBGPW3/koELb+ZJjCqPpWC qZxuYeXeIAltMYRy/87CzPJi2r+S1mYTFlgnVfRV5UbrA/nMOLMm1DGwAHxr+YOL8QvTcK dnSI+WMXIdjpcNnipTHtYAFoUyuDT88= X-MC-Unique: jm_o4ewrOs-JZ9S_TBMGTQ-1 From: Nir Soffer To: qemu-devel@nongnu.org Cc: Thomas Huth , Paolo Bonzini , Kevin Wolf , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , qemu-block@nongnu.org, =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Hanna Reitz , Nir Soffer Subject: [PATCH v2 2/5] Support format or cache specific out file Date: Mon, 28 Nov 2022 16:15:11 +0200 Message-Id: <20221128141514.388724-3-nsoffer@redhat.com> In-Reply-To: <20221128141514.388724-1-nsoffer@redhat.com> References: <20221128141514.388724-1-nsoffer@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 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=170.10.133.124; envelope-from=nsoffer@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_H2=-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.29 Precedence: list List-Id: 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: 1669645150462100001 Content-Type: text/plain; charset="utf-8" Extend the test finder to find tests with format (*.out.qcow2) or cache specific (*.out.nocache) out file. This worked before only for the numbered tests. --- tests/qemu-iotests/findtests.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/findtests.py b/tests/qemu-iotests/findtests= .py index dd77b453b8..f4344ce78c 100644 --- a/tests/qemu-iotests/findtests.py +++ b/tests/qemu-iotests/findtests.py @@ -38,31 +38,37 @@ def chdir(path: Optional[str] =3D None) -> Iterator[Non= e]: os.chdir(saved_dir) =20 =20 class TestFinder: def __init__(self, test_dir: Optional[str] =3D None) -> None: self.groups =3D defaultdict(set) =20 with chdir(test_dir): self.all_tests =3D glob.glob('[0-9][0-9][0-9]') self.all_tests +=3D [f for f in glob.iglob('tests/*') - if not f.endswith('.out') and - os.path.isfile(f + '.out')] + if self.is_test(f)] =20 for t in self.all_tests: with open(t, encoding=3D"utf-8") as f: for line in f: if line.startswith('# group: '): for g in line.split()[2:]: self.groups[g].add(t) break =20 + def is_test(self, fname: str) -> bool: + """ + The tests directory contains tests (no extension) and out files + (*.out, *.out.{format}, *.out.{option}). + """ + return re.search(r'.+\.out(\.\w+)?$', fname) is None + def add_group_file(self, fname: str) -> None: with open(fname, encoding=3D"utf-8") as f: for line in f: line =3D line.strip() =20 if (not line) or line[0] =3D=3D '#': continue =20 words =3D line.split() test_file =3D self.parse_test_name(words[0]) --=20 2.38.1 From nobody Sat Apr 27 21:47:10 2024 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1669645056; cv=none; d=zohomail.com; s=zohoarc; b=leEwx41MGHdBStvukJp91D5BsO4LXFVS69kYQcFYsUJHOiC4J3gCMHv+Z86VQy7VOGHTo6DKlzL88nijels7dnqhIui/hnkR9JG8gJ+8eNX0gAMYtn2vlwTLW4FqQCxlVfNOM4agLNnIM16N/CgSwJXWI3aA3AzuFhC2Yc7gx8o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1669645056; 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=7x2mC6FQA5jtF4ZAuEYUuB2a0IjYhd/qHy1kurSLbZ4=; b=eI2gu9k/MZ8EY22L5GbCtv5GiE0+Vq0WzGhqiXbW80AH/4b2cdWP74xS8NqmlcGY9O65L/MYosaDD4FYeVcJQoSrNj1x4ghH66050/X3xadF7mtWv7HuZ6NdoRKlZ2k2/RmdcY1EkgVPc5aDfEvpxWpkmiT9sg2F8p+NLTXRMzc= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1669645056619734.6200274992841; Mon, 28 Nov 2022 06:17:36 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ozewB-0008OL-5E; Mon, 28 Nov 2022 09:16:47 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ozevV-0008D1-G1 for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:10 -0500 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 1ozevR-0005SD-3o for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:04 -0500 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-190-F2gDD2W_P8eIOAM1r1WArA-1; Mon, 28 Nov 2022 09:15:57 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id D53AA108C1D4; Mon, 28 Nov 2022 14:15:23 +0000 (UTC) Received: from loop.redhat.com (unknown [10.35.206.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id C51042166B46; Mon, 28 Nov 2022 14:15:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1669644960; 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=7x2mC6FQA5jtF4ZAuEYUuB2a0IjYhd/qHy1kurSLbZ4=; b=iyXSW1bKpynYYftxFbLKQfitznCAWoZPboSzgPBUvrkhk9VPYYZNTM4nBNj9XhC/JptpYF UVvVFa//bH9quGN9c15rYbA7inbVe0T/iZ/znotvHs95Cjyj75w7Zpu4Dl2STR3eJxEXkx uHUELCNcYZp/FlXYG7sW7DBQFYl9DiM= X-MC-Unique: F2gDD2W_P8eIOAM1r1WArA-1 From: Nir Soffer To: qemu-devel@nongnu.org Cc: Thomas Huth , Paolo Bonzini , Kevin Wolf , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , qemu-block@nongnu.org, =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Hanna Reitz , Nir Soffer Subject: [PATCH v2 3/5] qemu-img: Add checksum command Date: Mon, 28 Nov 2022 16:15:12 +0200 Message-Id: <20221128141514.388724-4-nsoffer@redhat.com> In-Reply-To: <20221128141514.388724-1-nsoffer@redhat.com> References: <20221128141514.388724-1-nsoffer@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 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=170.10.133.124; envelope-from=nsoffer@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_H2=-0.001, SPF_HELO_NONE=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: 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: 1669645142532100001 The checksum command compute a checksum for disk image content using the blkhash library[1]. The blkhash library is not packaged yet, but it is available via copr[2]. Example run: $ ./qemu-img checksum -p fedora-35.qcow2 6e5c00c995056319d52395f8d91c7f84725ae3da69ffcba4de4c7d22cff713a5 fedor= a-35.qcow2 The block checksum is constructed by splitting the image to fixed sized blocks and computing a digest of every block. The image checksum is the digest of the all block digests. The checksum uses internally the "sha256" algorithm but it cannot be compared with checksums created by other tools such as `sha256sum`. The blkhash library supports sparse images, zero detection, and optimizes zero block hashing (they are practically free). The library uses multiple threads to speed up the computation. Comparing to `sha256sum`, `qemu-img checksum` is 3.5-4800[3] times faster, depending on the amount of data in the image: $ ./qemu-img info /scratch/50p.raw file format: raw virtual size: 6 GiB (6442450944 bytes) disk size: 2.91 GiB $ hyperfine -w2 -r5 -p "sleep 1" "./qemu-img checksum /scratch/50p.raw"= \ "sha256sum /scratch/50p.raw" Benchmark 1: ./qemu-img checksum /scratch/50p.raw Time (mean =C2=B1 =CF=83): 1.849 s =C2=B1 0.037 s [User: 7.7= 64 s, System: 0.962 s] Range (min =E2=80=A6 max): 1.813 s =E2=80=A6 1.908 s 5 runs Benchmark 2: sha256sum /scratch/50p.raw Time (mean =C2=B1 =CF=83): 14.585 s =C2=B1 0.072 s [User: 13.= 537 s, System: 1.003 s] Range (min =E2=80=A6 max): 14.501 s =E2=80=A6 14.697 s 5 runs Summary './qemu-img checksum /scratch/50p.raw' ran 7.89 =C2=B1 0.16 times faster than 'sha256sum /scratch/50p.raw' The new command is available only when `blkhash` is available during build. To test the new command please install the `blkhash-devel` package: $ dnf copr enable nsoffer/blkhash $ sudo dnf install blkhash-devel [1] https://gitlab.com/nirs/blkhash [2] https://copr.fedorainfracloud.org/coprs/nsoffer/blkhash/ [3] Computing checksum for 8T empty image: qemu-img checksum: 3.7s, sha256sum (estimate): 17,749s Signed-off-by: Nir Soffer Reviewed-by: Hanna Reitz --- docs/tools/qemu-img.rst | 24 ++++++ meson.build | 10 ++- meson_options.txt | 2 + qemu-img-cmds.hx | 8 ++ qemu-img.c | 183 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 1 deletion(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 15aeddc6d8..d856785ecc 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -347,20 +347,44 @@ Command description: Check completed, image is corrupted 3 Check completed, image has leaked clusters, but is not corrupted 63 Checks are not supported by the image format =20 If ``-r`` is specified, exit codes representing the image state refer to= the state after (the attempt at) repairing it. That is, a successful ``-r al= l`` will yield the exit code 0, independently of the image state before. =20 +.. option:: checksum [--object OBJECTDEF] [--image-opts] [-f FMT] [-T SRC_= CACHE] [-p] FILENAME + + Print a checksum for image *FILENAME* guest visible content. Images with + different format or settings will have the same checksum. + + The format is probed unless you specify it by ``-f``. + + The checksum is computed for guest visible content. Allocated areas full= of + zeroes, zero clusters, and unallocated areas are read as zeros so they w= ill + have the same checksum. Images with single or multiple files or backing = files + will have the same checksums if the guest will see the same content when + reading the image. + + Image metadata that is not visible to the guest such as dirty bitmaps do= es + not affect the checksum. + + Computing a checksum requires a read-only image. You cannot compute a + checksum of an active image used by a guest, but you can compute a check= sum + of a guest during pull mode incremental backup using NBD URL. + + The checksum is not compatible with other tools such as *sha256sum* for + optimization purposes; using multithreading and optimized handling of ze= ro + areas. For more info please see https://gitlab.com/nirs/blkhash. + .. option:: commit [--object OBJECTDEF] [--image-opts] [-q] [-f FMT] [-t C= ACHE] [-b BASE] [-r RATE_LIMIT] [-d] [-p] FILENAME =20 Commit the changes recorded in *FILENAME* in its base image or backing f= ile. If the backing file is smaller than the snapshot, then the backing file = will be resized to be the same size as the snapshot. If the snapshot is smaller= than the backing file, the backing file will not be truncated. If you want t= he backing file to match the size of the smaller snapshot, you can safely t= runcate it yourself once the commit operation successfully completes. =20 The image *FILENAME* is emptied after the operation has succeeded. If yo= u do diff --git a/meson.build b/meson.build index 5c6b5a1c75..18071dd653 100644 --- a/meson.build +++ b/meson.build @@ -790,20 +790,24 @@ if not get_option('curl').auto() or have_block kwargs: static_kwargs) endif libudev =3D not_found if targetos =3D=3D 'linux' and (have_system or have_tools) libudev =3D dependency('libudev', method: 'pkg-config', required: get_option('libudev'), kwargs: static_kwargs) endif =20 +blkhash =3D dependency('blkhash', version: '>=3D0.5.1', + method: 'pkg-config', + required: get_option('blkhash')) + mpathlibs =3D [libudev] mpathpersist =3D not_found mpathpersist_new_api =3D false if targetos =3D=3D 'linux' and have_tools and get_option('mpath').allowed() mpath_test_source_new =3D ''' #include #include unsigned mpath_mx_alloc_len =3D 1024; int logsink; static struct config *multipath_conf; @@ -1917,20 +1921,22 @@ config_host_data.set('CONFIG_CFI', get_option('cfi'= )) config_host_data.set('CONFIG_SELINUX', selinux.found()) config_host_data.set('CONFIG_XEN_BACKEND', xen.found()) if xen.found() # protect from xen.version() having less than three components xen_version =3D xen.version().split('.') + ['0', '0'] xen_ctrl_version =3D xen_version[0] + \ ('0' + xen_version[1]).substring(-2) + \ ('0' + xen_version[2]).substring(-2) config_host_data.set('CONFIG_XEN_CTRL_INTERFACE_VERSION', xen_ctrl_versi= on) endif +config_host_data.set('CONFIG_BLKHASH', blkhash.found()) + config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version(= ))) config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('= .')[0]) config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('= .')[1]) config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('= .')[2]) =20 config_host_data.set_quoted('CONFIG_HOST_DSOSUF', host_dsosuf) config_host_data.set('HAVE_HOST_BLOCK_DEVICE', have_host_block_device) =20 have_coroutine_pool =3D get_option('coroutine_pool') if get_option('debug_stack_usage') and have_coroutine_pool @@ -3582,21 +3588,22 @@ subdir('qga') # Don't build qemu-keymap if xkbcommon is not explicitly enabled # when we don't build tools or system if xkbcommon.found() # used for the update-keymaps target, so include rules even if !have_too= ls qemu_keymap =3D executable('qemu-keymap', files('qemu-keymap.c', 'ui/inp= ut-keymap.c') + genh, dependencies: [qemuutil, xkbcommon], install: h= ave_tools) endif =20 if have_tools qemu_img =3D executable('qemu-img', [files('qemu-img.c'), hxdep], - dependencies: [authz, block, crypto, io, qom, qemuutil], inst= all: true) + dependencies: [authz, block, crypto, io, qom, qemuutil, blkha= sh], + install: true) qemu_io =3D executable('qemu-io', files('qemu-io.c'), dependencies: [block, qemuutil], install: true) qemu_nbd =3D executable('qemu-nbd', files('qemu-nbd.c'), dependencies: [blockdev, qemuutil, gnutls, selinux], install: true) =20 subdir('storage-daemon') subdir('contrib/rdmacm-mux') subdir('contrib/elf2dmp') =20 @@ -3968,20 +3975,21 @@ summary_info +=3D {'bzip2 support': libbzip2} summary_info +=3D {'lzfse support': liblzfse} summary_info +=3D {'zstd support': zstd} summary_info +=3D {'NUMA host support': numa} summary_info +=3D {'capstone': capstone} summary_info +=3D {'libpmem support': libpmem} summary_info +=3D {'libdaxctl support': libdaxctl} summary_info +=3D {'libudev': libudev} # Dummy dependency, keep .found() summary_info +=3D {'FUSE lseek': fuse_lseek.found()} summary_info +=3D {'selinux': selinux} +summary_info +=3D {'blkhash': blkhash} summary(summary_info, bool_yn: true, section: 'Dependencies') =20 if not supported_cpus.contains(cpu) message() warning('SUPPORT FOR THIS HOST CPU WILL GO AWAY IN FUTURE RELEASES!') message() message('CPU host architecture ' + cpu + ' support is not currently main= tained.') message('The QEMU project intends to remove support for this host CPU in= ') message('a future release if nobody volunteers to maintain it and to') message('provide a build host for our continuous integration setup.') diff --git a/meson_options.txt b/meson_options.txt index 4b749ca549..475ddcf211 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -314,10 +314,12 @@ option('debug_mutex', type: 'boolean', value: false, option('debug_stack_usage', type: 'boolean', value: false, description: 'measure coroutine stack usage') option('qom_cast_debug', type: 'boolean', value: false, description: 'cast debugging support') option('gprof', type: 'boolean', value: false, description: 'QEMU profiling with gprof') option('profiler', type: 'boolean', value: false, description: 'profiler support') option('slirp_smbd', type : 'feature', value : 'auto', description: 'use smbd (at path --smbd=3D*) in slirp networking') +option('blkhash', type: 'feature', value: 'auto', + description: 'blkhash support for computing image checksum') diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 1b1dab5b17..c4fc935a37 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -26,20 +26,28 @@ DEF("bitmap", img_bitmap, SRST .. option:: bitmap (--merge SOURCE | --add | --remove | --clear | --enable= | --disable)... [-b SOURCE_FILE [-F SOURCE_FMT]] [-g GRANULARITY] [--objec= t OBJECTDEF] [--image-opts | -f FMT] FILENAME BITMAP ERST =20 DEF("check", img_check, "check [--object objectdef] [--image-opts] [-q] [-f fmt] [--output=3Do= fmt] [-r [leaks | all]] [-T src_cache] [-U] filename") SRST .. option:: check [--object OBJECTDEF] [--image-opts] [-q] [-f FMT] [--out= put=3DOFMT] [-r [leaks | all]] [-T SRC_CACHE] [-U] FILENAME ERST =20 +#ifdef CONFIG_BLKHASH +DEF("checksum", img_checksum, + "checksum [--object objectdef] [--image-opts] [-f fmt] [-T src_cache] = [-p] filename") +SRST +.. option:: checksum [--object OBJECTDEF] [--image-opts] [-f FMT] [-T SRC_= CACHE] [-p] FILENAME +ERST +#endif /* CONFIG_BLKHASH */ + DEF("commit", img_commit, "commit [--object objectdef] [--image-opts] [-q] [-f fmt] [-t cache] [= -b base] [-r rate_limit] [-d] [-p] filename") SRST .. option:: commit [--object OBJECTDEF] [--image-opts] [-q] [-f FMT] [-t C= ACHE] [-b BASE] [-r RATE_LIMIT] [-d] [-p] FILENAME ERST =20 DEF("compare", img_compare, "compare [--object objectdef] [--image-opts] [-f fmt] [-F fmt] [-T src= _cache] [-p] [-q] [-s] [-U] filename1 filename2") SRST .. option:: compare [--object OBJECTDEF] [--image-opts] [-f FMT] [-F FMT] = [-T SRC_CACHE] [-p] [-q] [-s] [-U] FILENAME1 FILENAME2 diff --git a/qemu-img.c b/qemu-img.c index c03d6b4b31..4b4ca7add3 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -18,20 +18,24 @@ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN * THE SOFTWARE. */ =20 #include "qemu/osdep.h" #include =20 +#ifdef CONFIG_BLKHASH +#include +#endif + #include "qemu/help-texts.h" #include "qemu/qemu-progress.h" #include "qemu-version.h" #include "qapi/error.h" #include "qapi/qapi-commands-block-core.h" #include "qapi/qapi-visit-block-core.h" #include "qapi/qobject-output-visitor.h" #include "qapi/qmp/qjson.h" #include "qapi/qmp/qdict.h" #include "qemu/cutils.h" @@ -1613,20 +1617,199 @@ out: qemu_vfree(buf1); qemu_vfree(buf2); blk_unref(blk2); out2: blk_unref(blk1); out3: qemu_progress_end(); return ret; } =20 +#ifdef CONFIG_BLKHASH +/* + * Compute image checksum. + */ +static int img_checksum(int argc, char **argv) +{ + const char *digest_name =3D "sha256"; + const size_t block_size =3D 64 * KiB; + + _Static_assert(QEMU_IS_ALIGNED(IO_BUF_SIZE, block_size), + "IO_BUF_SIZE should be alligned to block_size"); + + const char *format =3D NULL; + const char *cache =3D BDRV_DEFAULT_CACHE; + const char *filename; + BlockBackend *blk; + BlockDriverState *bs; + uint8_t *buf =3D NULL; + bool progress =3D false; + int flags =3D 0; + bool writethrough; + int64_t total_size; + int64_t offset =3D 0; + int c; + bool image_opts =3D false; + struct blkhash *h =3D NULL; + unsigned char digest[64]; + unsigned int digest_len; + int err; + int exit_status =3D 1; + + for (;;) { + static const struct option long_options[] =3D { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {0, 0, 0, 0} + }; + c =3D getopt_long(argc, argv, ":hf:T:p", + long_options, NULL); + if (c =3D=3D -1) { + break; + } + switch (c) { + case ':': + missing_argument(argv[optind - 1]); + break; + case '?': + unrecognized_option(argv[optind - 1]); + break; + case 'h': + help(); + break; + case 'f': + format =3D optarg; + break; + case 'T': + cache =3D optarg; + break; + case 'p': + progress =3D true; + break; + case OPTION_OBJECT: + user_creatable_process_cmdline(optarg); + break; + case OPTION_IMAGE_OPTS: + image_opts =3D true; + break; + } + } + + if (optind !=3D argc - 1) { + error_exit("Expecting image file name"); + } + + filename =3D argv[optind++]; + + err =3D bdrv_parse_cache_mode(cache, &flags, &writethrough); + if (err < 0) { + error_report("Invalid source cache option: %s", cache); + return exit_status; + } + + blk =3D img_open(image_opts, filename, format, flags, writethrough, fa= lse, + false); + if (!blk) { + return exit_status; + } + + /* Initialize before using goto out. */ + qemu_progress_init(progress, 2.0); + + bs =3D blk_bs(blk); + buf =3D blk_blockalign(blk, IO_BUF_SIZE); + + total_size =3D blk_getlength(blk); + if (total_size < 0) { + error_report("Can't get size of %s: %s", + filename, strerror(-total_size)); + goto out; + } + + h =3D blkhash_new(block_size, digest_name); + if (!h) { + error_report("Can't create blkhash: %s", strerror(errno)); + goto out; + } + + qemu_progress_print(0, 100); + + while (offset < total_size) { + int status; + int64_t chunk; + + status =3D bdrv_block_status_above(bs, NULL, offset, + total_size - offset, &chunk, NULL, + NULL); + if (status < 0) { + error_report("Error checking status at offset %" PRId64 " for = %s", + offset, filename); + goto out; + } + + assert(chunk); + + if (status & BDRV_BLOCK_ZERO) { + chunk =3D MIN(chunk, SIZE_MAX); + err =3D blkhash_zero(h, chunk); + if (err) { + error_report("Error zeroing hash at offset %" PRId64 + " of %s: %s", + offset, filename, strerror(err)); + goto out; + } + } else { + chunk =3D MIN(chunk, IO_BUF_SIZE); + err =3D blk_pread(blk, offset, chunk, buf, 0); + if (err < 0) { + error_report("Error reading at offset %" PRId64 " of %s: %= s", + offset, filename, strerror(-err)); + goto out; + } + err =3D blkhash_update(h, buf, chunk); + if (err) { + error_report("Error updating hash at offset %" PRId64 + " of %s: %s", + offset, filename, strerror(err)); + goto out; + } + } + + offset +=3D chunk; + qemu_progress_print(((float) chunk / total_size) * 100, 100); + } + + err =3D blkhash_final(h, digest, &digest_len); + if (err) { + error_report("Error finalizing hash of %s: %s", + filename, strerror(err)); + goto out; + } + + for (unsigned i =3D 0; i < digest_len; i++) { + printf("%02x", digest[i]); + } + printf(" %s%s", filename, progress ? "" : "\n"); + + exit_status =3D 0; + +out: + blkhash_free(h); + qemu_vfree(buf); + blk_unref(blk); + qemu_progress_end(); + + return exit_status; +} +#endif /* CONFIG_BLKHASH */ + /* Convenience wrapper around qmp_block_dirty_bitmap_merge */ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_na= me, const char *src_node, const char *src_na= me, Error **errp) { BlockDirtyBitmapOrStr *merge_src; BlockDirtyBitmapOrStrList *list =3D NULL; =20 merge_src =3D g_new0(BlockDirtyBitmapOrStr, 1); merge_src->type =3D QTYPE_QDICT; --=20 2.38.1 From nobody Sat Apr 27 21:47:10 2024 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1669645086; cv=none; d=zohomail.com; s=zohoarc; b=Ah8c9y8DFIlyLH7NeDFv7sMZmSZl47J+1GuHVMc2tSMdbA2UHGju/DEIMkfzP+PXE2t73/EryNIacH1ZSTRtLJzy39ElGVCuyq00hrZ8YfosQcQJEGjQDlI/Fjdk/dkrXBiU8oOamMhXfpFz30MkJoaOLaQlizKiJp4mc0gxMJs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1669645086; h=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=KEZwO46uDaY3GxoK7rTkj6GzQamI/aMOXzkbw53IhQw=; b=ZTERClCjYhOvtZ6PCl7YfKmOmZce6EUczVMcOQonwiP4B/c+Hu6R9Y28JyP4KyJclVVC2f58gWnhuWUvzdDpW05XCFLv+DRqxOrj6xl+oHUuNKyTCBWV3BCFe/bt79wqIfCxcjzniRA8mU1HrTc4rdVtvlooe/lf9UbF9NoFurM= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1669645086078667.956671693219; Mon, 28 Nov 2022 06:18:06 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ozew9-0008Ny-HM; Mon, 28 Nov 2022 09:16:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ozevX-0008DY-C9 for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:12 -0500 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 1ozevU-0005Sy-CM for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:06 -0500 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-277-rep5zv2GNP2vKtw-ktOJdQ-1; Mon, 28 Nov 2022 09:16:02 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1A60E877CB8; Mon, 28 Nov 2022 14:15:26 +0000 (UTC) Received: from loop.redhat.com (unknown [10.35.206.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2DED82166B2E; Mon, 28 Nov 2022 14:15:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1669644963; 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=KEZwO46uDaY3GxoK7rTkj6GzQamI/aMOXzkbw53IhQw=; b=iv9Rcqmy9JJCfjPT/1iKO3JG+wmw86n8rIEAMZcAdHxZBZ6+w1YoNVXeRoOSB90vh6RlCg QdrouCMnNa518xiaCGBK2Fo1KT43J2tWJsG/Y0VWTOUiTbL9xOLew2EqqhQt7gA8/HJYqX ae5yLgsTeoOZwD+0Up/CTcIC/jB9sqs= X-MC-Unique: rep5zv2GNP2vKtw-ktOJdQ-1 From: Nir Soffer To: qemu-devel@nongnu.org Cc: Thomas Huth , Paolo Bonzini , Kevin Wolf , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , qemu-block@nongnu.org, =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Hanna Reitz , Nir Soffer Subject: [PATCH v2 4/5] iotests: Test qemu-img checksum Date: Mon, 28 Nov 2022 16:15:13 +0200 Message-Id: <20221128141514.388724-5-nsoffer@redhat.com> In-Reply-To: <20221128141514.388724-1-nsoffer@redhat.com> References: <20221128141514.388724-1-nsoffer@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 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=170.10.129.124; envelope-from=nsoffer@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_H2=-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.29 Precedence: list List-Id: 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: 1669645179854100001 Content-Type: text/plain; charset="utf-8" Add simple tests computing a checksum for image with all kinds of extents in raw and qcow2 formats. The test can be extended later for other formats, format options (e..g compressed qcow2), protocols (e.g. nbd), and image with a backing chain, but I'm not sure this is really needed. To help debugging in case of failures, the output includes a json map of the test image. Signed-off-by: Nir Soffer Reviewed-by: Hanna Reitz --- tests/qemu-iotests/tests/qemu-img-checksum | 63 +++++++++++++++++++ .../tests/qemu-img-checksum.out.qcow2 | 11 ++++ .../tests/qemu-img-checksum.out.raw | 10 +++ 3 files changed, 84 insertions(+) create mode 100755 tests/qemu-iotests/tests/qemu-img-checksum create mode 100644 tests/qemu-iotests/tests/qemu-img-checksum.out.qcow2 create mode 100644 tests/qemu-iotests/tests/qemu-img-checksum.out.raw diff --git a/tests/qemu-iotests/tests/qemu-img-checksum b/tests/qemu-iotest= s/tests/qemu-img-checksum new file mode 100755 index 0000000000..3577a0bc41 --- /dev/null +++ b/tests/qemu-iotests/tests/qemu-img-checksum @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# group: rw auto quick +# +# Test cases for qemu-img checksum. +# +# 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 re + +import iotests + +from iotests import ( + filter_testfiles, + qemu_img, + qemu_img_log, + qemu_io, +) + + +def checksum_available(): + out =3D qemu_img("--help").stdout + return re.search(r"\bchecksum .+ filename\b", out) is not None + + +if not checksum_available(): + iotests.notrun("checksum command not available") + +iotests.script_initialize( + supported_fmts=3D["raw", "qcow2"], + supported_cache_modes=3D["none", "writeback"], + supported_protocols=3D["file"], +) + +print("=3D=3D=3D Create test image =3D=3D=3D\n") + +disk =3D iotests.file_path('disk') +qemu_img("create", "-f", iotests.imgfmt, disk, "10m") +qemu_io("-f", iotests.imgfmt, + "-c", "write -P 0x1 0 2m", # data + "-c", "write -P 0x0 2m 2m", # data with zeroes + "-c", "write -z 4m 2m", # zero allocated + "-c", "write -z -u 6m 2m", # zero hole + # unallocated + disk) +print(filter_testfiles(disk)) +qemu_img_log("map", "--output", "json", disk) + +print("=3D=3D=3D Compute checksum =3D=3D=3D\n") + +qemu_img_log("checksum", "-T", iotests.cachemode, disk) diff --git a/tests/qemu-iotests/tests/qemu-img-checksum.out.qcow2 b/tests/q= emu-iotests/tests/qemu-img-checksum.out.qcow2 new file mode 100644 index 0000000000..02b9616e5b --- /dev/null +++ b/tests/qemu-iotests/tests/qemu-img-checksum.out.qcow2 @@ -0,0 +1,11 @@ +=3D=3D=3D Create test image =3D=3D=3D + +TEST_DIR/PID-disk +[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": fal= se, "data": true, "offset": 327680}, +{ "start": 4194304, "length": 4194304, "depth": 0, "present": true, "zero"= : true, "data": false}, +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero= ": true, "data": false}] + +=3D=3D=3D Compute checksum =3D=3D=3D + +57cd8ef0cfad106d737f8fb0de3a0306a8a1a41db7bf7c0c36e2dfe75ee9bd26 TEST_DIR= /PID-disk + diff --git a/tests/qemu-iotests/tests/qemu-img-checksum.out.raw b/tests/qem= u-iotests/tests/qemu-img-checksum.out.raw new file mode 100644 index 0000000000..6294e4dace --- /dev/null +++ b/tests/qemu-iotests/tests/qemu-img-checksum.out.raw @@ -0,0 +1,10 @@ +=3D=3D=3D Create test image =3D=3D=3D + +TEST_DIR/PID-disk +[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": fal= se, "data": true, "offset": 0}, +{ "start": 4194304, "length": 6291456, "depth": 0, "present": true, "zero"= : true, "data": false, "offset": 4194304}] + +=3D=3D=3D Compute checksum =3D=3D=3D + +57cd8ef0cfad106d737f8fb0de3a0306a8a1a41db7bf7c0c36e2dfe75ee9bd26 TEST_DIR= /PID-disk + --=20 2.38.1 From nobody Sat Apr 27 21:47:10 2024 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1669645071; cv=none; d=zohomail.com; s=zohoarc; b=GtvvbqM6DxoyMa+Lu5PSCrIrVSl9wtxbfMPmxpMcQpsVejUPxG59wl5POfEjA+fO8Q2ifJpLbvglddsAZymbW6Ys2RbJAgIk67DBtYsiPn1yPcCQa+X+eqV934WsMmH6a0KX/ru+a0sMcUh825VHa0BGrio91nIhT0YPZqekQBo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1669645071; 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=p0KdchlVYDcnHCQp92NisCCanindp9rcWGshdvmSyVI=; b=kG/dOtCceFsUI9Qoy8N2Sv6iv24Q3xOsyLyJvfjGypAlV/PyAOjN1fxtOkPq4HzmPgXOzYWr2OdzCBHNcORJk9IjdgewL9OcDWZUDip6O3NX+D55hMlvETidHvLSVMUA4Lh3B8V/Y/pYn1Dl0vehORvlA5CsWjI7P+NJc34gELw= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1669645071189728.4581335514481; Mon, 28 Nov 2022 06:17:51 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ozew2-0008Ln-PE; Mon, 28 Nov 2022 09:16:39 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ozevU-0008Bx-KJ for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:08 -0500 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 1ozevS-0005SP-3c for qemu-devel@nongnu.org; Mon, 28 Nov 2022 09:16:04 -0500 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-299-7fjppPDUMN-398RoeE4Qqw-1; Mon, 28 Nov 2022 09:15:57 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7F015948F9C; Mon, 28 Nov 2022 14:15:28 +0000 (UTC) Received: from loop.redhat.com (unknown [10.35.206.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 659DF2166B36; Mon, 28 Nov 2022 14:15:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1669644961; 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=p0KdchlVYDcnHCQp92NisCCanindp9rcWGshdvmSyVI=; b=bk0xZ4LV0F5Zu5Hu733ntb5v3bdCzz6dZ2Q1p+Rar062Nuwc/2qox3hZRv5cG5jDuWI61e ERFIA5i9TXvzCCdAn2FmghuYgS28SRpHsCA7TNJES33PNW15cOXpRshQ5Xo8YFRk+cbx+W Rp6Bm9mdTNfVAcDQMjN3mIQvbWKQQl4= X-MC-Unique: 7fjppPDUMN-398RoeE4Qqw-1 From: Nir Soffer To: qemu-devel@nongnu.org Cc: Thomas Huth , Paolo Bonzini , Kevin Wolf , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , qemu-block@nongnu.org, =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Hanna Reitz , Nir Soffer Subject: [PATCH v2 5/5] qemu-img: Speed up checksum Date: Mon, 28 Nov 2022 16:15:14 +0200 Message-Id: <20221128141514.388724-6-nsoffer@redhat.com> In-Reply-To: <20221128141514.388724-1-nsoffer@redhat.com> References: <20221128141514.388724-1-nsoffer@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 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=170.10.129.124; envelope-from=nsoffer@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_H2=-0.001, SPF_HELO_NONE=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: 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: 1669645170052100001 Add coroutine based loop inspired by `qemu-img convert` design. Changes compared to `qemu-img convert`: - State for the entire image is kept in ImgChecksumState - State for single worker coroutine is kept in ImgChecksumworker. - "Writes" are always in-order, ensured using a queue. - Calling block status once per image extent, when the current extent is consumed by the workers. - Using 1m buffer size - testings shows that this gives best read performance both with buffered and direct I/O. - Number of coroutines is not configurable. Testing does not show improvement when using more than 8 coroutines. - Progress include entire image, not only the allocated state. Comparing to the simple read loop shows that this version is up to 4.67 times faster when computing a checksum for an image full of zeroes. For real images it is 1.59 times faster with direct I/O, and with buffered I/O there is no difference. Test results on Dell PowerEdge R640 in a CentOS Stream 9 container: | image | size | i/o | before | after | change | |----------|------|-----------|----------------|----------------|--------| | zero [1] | 6g | buffered | 1.600s =C2=B10.014s | 0.342s =C2=B10.016s |= x4.67 | | zero | 6g | direct | 4.684s =C2=B10.093s | 2.211s =C2=B10.009s |= x2.12 | | real [2] | 6g | buffered | 1.841s =C2=B10.075s | 1.806s =C2=B10.036s |= x1.02 | | real | 6g | direct | 3.094s =C2=B10.079s | 1.947s =C2=B10.017s |= x1.59 | | nbd [3] | 6g | buffered | 2.455s =C2=B10.183s | 1.808s =C2=B10.016s |= x1.36 | | nbd | 6g | direct | 3.540s =C2=B10.020s | 1.749s =C2=B10.018s |= x2.02 | [1] raw image full of zeroes [2] raw fedora 35 image with additional random data, 50% full [3] image [2] exported by qemu-nbd via unix socket Signed-off-by: Nir Soffer Reviewed-by: Hanna Reitz --- qemu-img.c | 350 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 277 insertions(+), 73 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 4b4ca7add3..5f63a769a9 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1618,50 +1618,296 @@ out: qemu_vfree(buf2); blk_unref(blk2); out2: blk_unref(blk1); out3: qemu_progress_end(); return ret; } =20 #ifdef CONFIG_BLKHASH + +#define CHECKSUM_COROUTINES 8 +#define CHECKSUM_BUF_SIZE (1 * MiB) +#define CHECKSUM_ZERO_SIZE MIN(16 * GiB, SIZE_MAX) + +typedef struct ImgChecksumState ImgChecksumState; + +typedef struct ImgChecksumWorker { + QTAILQ_ENTRY(ImgChecksumWorker) entry; + ImgChecksumState *state; + Coroutine *co; + uint8_t *buf; + + /* The current chunk. */ + int64_t offset; + int64_t length; + bool zero; + + /* + * Always true for zero extent, false for data extent. Set to true + * when reading the chunk completes. + */ + bool ready; +} ImgChecksumWorker; + +struct ImgChecksumState { + const char *filename; + BlockBackend *blk; + BlockDriverState *bs; + int64_t total_size; + + /* Current extent, modified in checksum_co_next. */ + int64_t offset; + int64_t length; + bool zero; + + int running_coroutines; + CoMutex lock; + ImgChecksumWorker workers[CHECKSUM_COROUTINES]; + + /* + * Ensure in-order updates. Update are scheduled at the tail of the + * queue and processed from the head of the queue when a worker is + * ready. + */ + QTAILQ_HEAD(, ImgChecksumWorker) update_queue; + + struct blkhash *hash; + int ret; +}; + +static int checksum_block_status(ImgChecksumState *s) +{ + int64_t length; + int status; + + /* Must be called when current extent is consumed. */ + assert(s->length =3D=3D 0); + + status =3D bdrv_block_status_above(s->bs, NULL, s->offset, + s->total_size - s->offset, &length, N= ULL, + NULL); + if (status < 0) { + error_report("Error checking status at offset %" PRId64 " for %s", + s->offset, s->filename); + s->ret =3D status; + return -1; + } + + assert(length > 0); + + s->length =3D length; + s->zero =3D !!(status & BDRV_BLOCK_ZERO); + + return 0; +} + +/** + * Grab the next chunk from the current extent, getting the next extent if + * needed, and schecule the next update at the end fo the update queue. + * + * Retrun true if the worker has work to do, false if the worker has + * finished or there was an error getting the next extent. + */ +static coroutine_fn bool checksum_co_next(ImgChecksumWorker *w) +{ + ImgChecksumState *s =3D w->state; + + qemu_co_mutex_lock(&s->lock); + + if (s->offset =3D=3D s->total_size || s->ret !=3D -EINPROGRESS) { + qemu_co_mutex_unlock(&s->lock); + return false; + } + + if (s->length =3D=3D 0 && checksum_block_status(s) < 0) { + qemu_co_mutex_unlock(&s->lock); + return false; + } + + /* Grab one chunk from current extent. */ + w->offset =3D s->offset; + w->length =3D MIN(s->length, + s->zero ? CHECKSUM_ZERO_SIZE : CHECKSUM_BUF_SIZE); + w->zero =3D s->zero; + w->ready =3D s->zero; + + /* Advance state to the next chunk. */ + s->offset +=3D w->length; + s->length -=3D w->length; + + /* Schedule this chunk update. */ + QTAILQ_INSERT_TAIL(&s->update_queue, w, entry); + + qemu_co_mutex_unlock(&s->lock); + + return true; +} + +/* Wait until this chunk is in the head of the update queue. */ +static void coroutine_fn checksum_co_wait_for_update(ImgChecksumWorker *w) +{ + ImgChecksumState *s =3D w->state; + + /* Must be called only when we are ready to update the hash. */ + assert(w->ready); + + while (QTAILQ_FIRST(&s->update_queue) !=3D w) { + qemu_coroutine_yield(); + } + + QTAILQ_REMOVE(&s->update_queue, w, entry); +} + +/* Enter the next worker coroutine if the worker is ready. */ +static void coroutine_fn checksum_co_enter_next(ImgChecksumWorker *w) +{ + ImgChecksumState *s =3D w->state; + ImgChecksumWorker *next; + + if (!QTAILQ_EMPTY(&s->update_queue)) { + next =3D QTAILQ_FIRST(&s->update_queue); + if (next->ready) { + qemu_coroutine_enter(next->co); + } + } +} + +static int coroutine_fn checksum_co_read(ImgChecksumWorker *w) +{ + ImgChecksumState *s =3D w->state; + int err; + + err =3D blk_co_pread(s->blk, w->offset, w->length, w->buf, 0); + if (err < 0) { + error_report("Error reading at offset %" PRId64 " of %s: %s", + w->offset, s->filename, strerror(-err)); + /* Unschedule this chunk. */ + QTAILQ_REMOVE(&s->update_queue, w, entry); + s->ret =3D err; + return -1; + } + + w->ready =3D true; + + return 0; +} + +static int checksum_update_hash(ImgChecksumWorker *w) +{ + ImgChecksumState *s =3D w->state; + int err; + + if (w->zero) { + err =3D blkhash_zero(s->hash, w->length); + if (err) { + error_report("Error zeroing hash at offset %" PRId64 " of %s: = %s", + w->offset, s->filename, strerror(err)); + s->ret =3D -err; + return -1; + } + } else { + err =3D blkhash_update(s->hash, w->buf, w->length); + if (err) { + error_report("Error updating hash at offset %" PRId64 " of %s:= %s", + w->offset, s->filename, strerror(err)); + s->ret =3D -err; + return -1; + } + } + + return 0; +} + +static void coroutine_fn checksum_co_loop(void *opaque) +{ + ImgChecksumWorker *w =3D opaque; + ImgChecksumState *s =3D w->state; + + s->running_coroutines++; + w->buf =3D blk_blockalign(s->blk, CHECKSUM_BUF_SIZE); + + while (checksum_co_next(w)) { + if (!w->zero && checksum_co_read(w) < 0) { + break; + } + checksum_co_wait_for_update(w); + if (s->ret =3D=3D -EINPROGRESS) { + if (checksum_update_hash(w) < 0) { + break; + } + qemu_progress_print(((float) w->length / s->total_size) * 100,= 100); + } + checksum_co_enter_next(w); + } + + qemu_vfree(w->buf); + w->co =3D NULL; + s->running_coroutines--; + + if (s->running_coroutines =3D=3D 0 && s->ret =3D=3D -EINPROGRESS) { + /* the checksum job finished successfully */ + s->ret =3D 0; + } +} + +static int checksum_loop(ImgChecksumState *s) +{ + int i; + + s->ret =3D -EINPROGRESS; + + qemu_co_mutex_init(&s->lock); + QTAILQ_INIT(&s->update_queue); + + for (i =3D 0; i < CHECKSUM_COROUTINES; i++) { + ImgChecksumWorker *w =3D &s->workers[i]; + w->state =3D s; + w->co =3D qemu_coroutine_create(checksum_co_loop, w); + qemu_coroutine_enter(w->co); + } + + while (s->running_coroutines) { + main_loop_wait(false); + } + + return s->ret; +} + /* * Compute image checksum. */ static int img_checksum(int argc, char **argv) { const char *digest_name =3D "sha256"; const size_t block_size =3D 64 * KiB; =20 - _Static_assert(QEMU_IS_ALIGNED(IO_BUF_SIZE, block_size), - "IO_BUF_SIZE should be alligned to block_size"); + _Static_assert(QEMU_IS_ALIGNED(CHECKSUM_BUF_SIZE, block_size), + "CHECKSUM_BUF_SIZE should be alligned to block_size"); =20 const char *format =3D NULL; const char *cache =3D BDRV_DEFAULT_CACHE; - const char *filename; - BlockBackend *blk; - BlockDriverState *bs; - uint8_t *buf =3D NULL; bool progress =3D false; + bool image_opts =3D false; + int flags =3D 0; - bool writethrough; - int64_t total_size; - int64_t offset =3D 0; + bool writethrough =3D false; int c; - bool image_opts =3D false; - struct blkhash *h =3D NULL; - unsigned char digest[64]; - unsigned int digest_len; + int err; int exit_status =3D 1; =20 + ImgChecksumState s =3D {0}; + unsigned char digest[64]; + unsigned int digest_len; + for (;;) { static const struct option long_options[] =3D { {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c =3D getopt_long(argc, argv, ":hf:T:p", long_options, NULL); if (c =3D=3D -1) { @@ -1692,118 +1938,76 @@ static int img_checksum(int argc, char **argv) case OPTION_IMAGE_OPTS: image_opts =3D true; break; } } =20 if (optind !=3D argc - 1) { error_exit("Expecting image file name"); } =20 - filename =3D argv[optind++]; + s.filename =3D argv[optind++]; =20 err =3D bdrv_parse_cache_mode(cache, &flags, &writethrough); if (err < 0) { error_report("Invalid source cache option: %s", cache); return exit_status; } =20 - blk =3D img_open(image_opts, filename, format, flags, writethrough, fa= lse, - false); - if (!blk) { + s.blk =3D img_open(image_opts, s.filename, format, flags, writethrough, + false, false); + if (!s.blk) { return exit_status; } =20 /* Initialize before using goto out. */ qemu_progress_init(progress, 2.0); =20 - bs =3D blk_bs(blk); - buf =3D blk_blockalign(blk, IO_BUF_SIZE); + s.bs =3D blk_bs(s.blk); =20 - total_size =3D blk_getlength(blk); - if (total_size < 0) { + s.total_size =3D blk_getlength(s.blk); + if (s.total_size < 0) { error_report("Can't get size of %s: %s", - filename, strerror(-total_size)); + s.filename, strerror(-s.total_size)); goto out; } =20 - h =3D blkhash_new(block_size, digest_name); - if (!h) { + s.hash =3D blkhash_new(block_size, digest_name); + if (!s.hash) { error_report("Can't create blkhash: %s", strerror(errno)); goto out; } =20 qemu_progress_print(0, 100); =20 - while (offset < total_size) { - int status; - int64_t chunk; - - status =3D bdrv_block_status_above(bs, NULL, offset, - total_size - offset, &chunk, NULL, - NULL); - if (status < 0) { - error_report("Error checking status at offset %" PRId64 " for = %s", - offset, filename); - goto out; - } - - assert(chunk); - - if (status & BDRV_BLOCK_ZERO) { - chunk =3D MIN(chunk, SIZE_MAX); - err =3D blkhash_zero(h, chunk); - if (err) { - error_report("Error zeroing hash at offset %" PRId64 - " of %s: %s", - offset, filename, strerror(err)); - goto out; - } - } else { - chunk =3D MIN(chunk, IO_BUF_SIZE); - err =3D blk_pread(blk, offset, chunk, buf, 0); - if (err < 0) { - error_report("Error reading at offset %" PRId64 " of %s: %= s", - offset, filename, strerror(-err)); - goto out; - } - err =3D blkhash_update(h, buf, chunk); - if (err) { - error_report("Error updating hash at offset %" PRId64 - " of %s: %s", - offset, filename, strerror(err)); - goto out; - } - } - - offset +=3D chunk; - qemu_progress_print(((float) chunk / total_size) * 100, 100); + err =3D checksum_loop(&s); + if (err) { + goto out; } =20 - err =3D blkhash_final(h, digest, &digest_len); + err =3D blkhash_final(s.hash, digest, &digest_len); if (err) { error_report("Error finalizing hash of %s: %s", - filename, strerror(err)); + s.filename, strerror(err)); goto out; } =20 for (unsigned i =3D 0; i < digest_len; i++) { printf("%02x", digest[i]); } - printf(" %s%s", filename, progress ? "" : "\n"); + printf(" %s%s", s.filename, progress ? "" : "\n"); =20 exit_status =3D 0; =20 out: - blkhash_free(h); - qemu_vfree(buf); - blk_unref(blk); + blkhash_free(s.hash); + blk_unref(s.blk); qemu_progress_end(); =20 return exit_status; } #endif /* CONFIG_BLKHASH */ =20 /* Convenience wrapper around qmp_block_dirty_bitmap_merge */ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_na= me, const char *src_node, const char *src_na= me, Error **errp) --=20 2.38.1