From nobody Mon Feb 9 00:30:41 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1621524114; cv=none; d=zohomail.com; s=zohoarc; b=OQxXFLNWiTRN7h1mmb9Hc9/wueiOv5f0SQuIF1HLyMA5bPfpgmpAugiZapCfcP8MrElfi1vTT8OaYTxAwLCeJTyjb/u/47zYIyo/Tn3DzhYaxO+7WrIRnMMGnfh4eMk99lO2tDVkdYyN/hCAl8BVisOO2KWIGpRl7fUb5pI/3AY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621524114; h=Content-Type:Content-Transfer-Encoding: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=lvcvc92WjshYIpKUKrv6qCaZt855iIN+nqq+wGkhuJ0=; b=UtXE+uZWUXnDO2yTH6Oa4YdjogjR71AGWyY1mpnUore9xJ+WEFM2DfSIiqR6P7kNBk7f3cSzrX7wpSPHLXgi0qavgD6JmqArOPjo8kk6bzrRUm7ixcsmSM4KjObXR3LffzPDZM6zxXFAGbR689E2i/B5B+BwSybDG4V8LHU8aF4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 162152411407530.06154452732528; Thu, 20 May 2021 08:21:54 -0700 (PDT) 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-410-fuy71KiNOJWzwi4kbIQrrQ-1; Thu, 20 May 2021 11:21:50 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 0D1BC8186F2; Thu, 20 May 2021 15:21:46 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DF9B260CCC; Thu, 20 May 2021 15:21:45 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id A88901801029; Thu, 20 May 2021 15:21:45 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 14KFEd3V017430 for ; Thu, 20 May 2021 11:14:39 -0400 Received: by smtp.corp.redhat.com (Postfix) id 8C62F19CBE; Thu, 20 May 2021 15:14:39 +0000 (UTC) Received: from antique-work.lan (unknown [10.40.194.173]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0B4D76062F for ; Thu, 20 May 2021 15:14:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1621524113; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=lvcvc92WjshYIpKUKrv6qCaZt855iIN+nqq+wGkhuJ0=; b=T8vbmhDl9u5h/h+EbS6vDq9M2GIQIEvS/AtdrCfftpv4mPcy8rmsRzuXNlL8pKSRBslJTv 53WSrV44NzVTz6mj3oxIGUqsELpxNv2FxeFPvWDwGFH+JsghKIwS+RdZ5fQl9z8BSjQeoL iW8BVIPY6U3a9Ps9qJ6GSt1agPPIqIs= X-MC-Unique: fuy71KiNOJWzwi4kbIQrrQ-1 From: Pavel Hrdina To: libvir-list@redhat.com Subject: [libvirt PATCH v2 2/2] storage_file: add support to probe cluster_size from QCOW2 images Date: Thu, 20 May 2021 17:14:32 +0200 Message-Id: <43f64666e416d76ae78646970463460bc9700406.1621523371.git.phrdina@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" >From QEMU docs/interop/qcow2.txt : Byte 20 - 23: cluster_bits Number of bits that are used for addressing an offset within a cluster (1 << cluster_bits is the cluster size= ). With this patch libvirt will be able to report the current cluster_size for all existing storage volumes managed by storage driver. Signed-off-by: Pavel Hrdina Reviewed-by: Peter Krempa --- Changes in v2: - Reworkded to use callback. src/storage/storage_util.c | 3 ++ src/storage_file/storage_file_probe.c | 70 ++++++++++++++++++++------- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index c8299852a3..a7c9355bf9 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -3483,6 +3483,9 @@ storageBackendProbeTarget(virStorageSource *target, if (meta->capacity) target->capacity =3D meta->capacity; =20 + if (meta->clusterSize > 0) + target->clusterSize =3D meta->clusterSize; + if (encryption && meta->encryption) { if (meta->encryption->payload_offset !=3D -1) target->capacity -=3D meta->encryption->payload_offset * 512; diff --git a/src/storage_file/storage_file_probe.c b/src/storage_file/stora= ge_file_probe.c index afe64da02e..07b7448bdd 100644 --- a/src/storage_file/storage_file_probe.c +++ b/src/storage_file/storage_file_probe.c @@ -95,6 +95,9 @@ struct FileTypeInfo { * or NULL if there is no COW base image, to RES; * return BACKING_STORE_* */ const struct FileEncryptionInfo *cryptInfo; /* Encryption info */ + unsigned long long (*getClusterSize)(const char *buf, + size_t buf_size, + int endian); int (*getBackingStore)(char **res, int *format, const char *buf, size_t buf_size); int (*getFeatures)(virBitmap **features, int format, @@ -104,6 +107,10 @@ struct FileTypeInfo { =20 static int cowGetBackingStore(char **, int *, const char *, size_t); +static unsigned long long +qcow2GetClusterSize(const char *buf, + size_t buf_size, + int endian); static int qcowXGetBackingStore(char **, int *, const char *, size_t); static int qcow2GetFeatures(virBitmap **features, int format, @@ -116,7 +123,8 @@ qedGetBackingStore(char **, int *, const char *, size_t= ); #define QCOWX_HDR_VERSION (4) #define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) #define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8) -#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4) +#define QCOWX_HDR_CLUSTER_BITS_OFFSET (QCOWX_HDR_BACKING_FILE_SIZE+4) +#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_CLUSTER_BITS_OFFSET+4) =20 #define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1+2) #define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8) @@ -238,18 +246,18 @@ static struct FileEncryptionInfo const qcow2Encryptio= nInfo[] =3D { =20 static struct FileTypeInfo const fileTypeInfo[] =3D { [VIR_STORAGE_FILE_NONE] =3D { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL, NUL= L }, [VIR_STORAGE_FILE_RAW] =3D { 0, NULL, LV_LITTLE_ENDIAN, -1, 0, {0}, 0, 0, 0, luksEncryptionInfo, - NULL, NULL }, + NULL, NULL, NULL }, [VIR_STORAGE_FILE_DIR] =3D { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL, NULL= }, [VIR_STORAGE_FILE_BOCHS] =3D { /*"Bochs Virtual HD Image", */ /* Untested */ 0, NULL, LV_LITTLE_ENDIAN, 64, 4, {0x20000}, - 32+16+16+4+4+4+4+4, 8, 1, NULL, NULL, NULL + 32+16+16+4+4+4+4+4, 8, 1, NULL, NULL, NULL, NULL }, [VIR_STORAGE_FILE_CLOOP] =3D { /* #!/bin/sh @@ -258,7 +266,7 @@ static struct FileTypeInfo const fileTypeInfo[] =3D { */ /* Untested */ 0, NULL, LV_LITTLE_ENDIAN, -1, 0, {0}, - -1, 0, 0, NULL, NULL, NULL + -1, 0, 0, NULL, NULL, NULL, NULL }, [VIR_STORAGE_FILE_DMG] =3D { /* XXX QEMU says there's no magic for dmg, @@ -266,51 +274,52 @@ static struct FileTypeInfo const fileTypeInfo[] =3D { * would have to match) but then disables that check. */ 0, NULL, 0, -1, 0, {0}, - -1, 0, 0, NULL, NULL, NULL + -1, 0, 0, NULL, NULL, NULL, NULL }, [VIR_STORAGE_FILE_ISO] =3D { 32769, "CD001", LV_LITTLE_ENDIAN, -2, 0, {0}, - -1, 0, 0, NULL, NULL, NULL + -1, 0, 0, NULL, NULL, NULL, NULL }, [VIR_STORAGE_FILE_VPC] =3D { 0, "conectix", LV_BIG_ENDIAN, 12, 4, {0x10000}, - 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, NULL, NULL, NULL + 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, NULL, NULL, NULL, NULL }, /* TODO: add getBackingStore function */ [VIR_STORAGE_FILE_VDI] =3D { 64, "\x7f\x10\xda\xbe", LV_LITTLE_ENDIAN, 68, 4, {0x00010001}, - 64 + 5 * 4 + 256 + 7 * 4, 8, 1, NULL, NULL, NULL}, + 64 + 5 * 4 + 256 + 7 * 4, 8, 1, NULL, NULL, NULL, NULL}, =20 /* Not direct file formats, but used for various drivers */ [VIR_STORAGE_FILE_FAT] =3D { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL, NULL= }, [VIR_STORAGE_FILE_VHD] =3D { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL, NULL= }, [VIR_STORAGE_FILE_PLOOP] =3D { 0, "WithouFreSpacExt", LV_LITTLE_ENDIAN, -2, 0, {0}, PLOOP_IMAGE_SIZE_OFFSET, 0, - PLOOP_SIZE_MULTIPLIER, NULL, NULL, NULL }, + PLOOP_SIZE_MULTIPLIER, NULL, NULL, NULL, = NULL }, =20 /* All formats with a backing store probe below here */ [VIR_STORAGE_FILE_COW] =3D { 0, "OOOM", LV_BIG_ENDIAN, 4, 4, {2}, - 4+4+1024+4, 8, 1, NULL, cowGetBackingStore, NULL + 4+4+1024+4, 8, 1, NULL, NULL, cowGetBackingStore, NULL }, [VIR_STORAGE_FILE_QCOW] =3D { 0, "QFI", LV_BIG_ENDIAN, 4, 4, {1}, QCOWX_HDR_IMAGE_SIZE, 8, 1, qcow1EncryptionInfo, - qcowXGetBackingStore, NULL + NULL, qcowXGetBackingStore, NULL }, [VIR_STORAGE_FILE_QCOW2] =3D { 0, "QFI", LV_BIG_ENDIAN, 4, 4, {2, 3}, QCOWX_HDR_IMAGE_SIZE, 8, 1, qcow2EncryptionInfo, + qcow2GetClusterSize, qcowXGetBackingStore, qcow2GetFeatures }, @@ -318,12 +327,12 @@ static struct FileTypeInfo const fileTypeInfo[] =3D { /* https://wiki.qemu.org/Features/QED */ 0, "QED", LV_LITTLE_ENDIAN, -2, 0, {0}, - QED_HDR_IMAGE_SIZE, 8, 1, NULL, qedGetBackingStore, NULL + QED_HDR_IMAGE_SIZE, 8, 1, NULL, NULL, qedGetBackingStore, NULL }, [VIR_STORAGE_FILE_VMDK] =3D { 0, "KDMV", LV_LITTLE_ENDIAN, 4, 4, {1, 2, 3}, - 4+4+4, 8, 512, NULL, vmdk4GetBackingStore, NULL + 4+4+4, 8, 512, NULL, NULL, vmdk4GetBackingStore, NULL }, }; G_STATIC_ASSERT(G_N_ELEMENTS(fileTypeInfo) =3D=3D VIR_STORAGE_FILE_LAST); @@ -468,6 +477,28 @@ qcow2GetExtensions(const char *buf, } =20 =20 +static unsigned long long +qcow2GetClusterSize(const char *buf, + size_t buf_size, + int endian) +{ + int clusterBits =3D 0; + + if ((QCOWX_HDR_CLUSTER_BITS_OFFSET + 4) > buf_size) + return 0; + + if (endian =3D=3D LV_LITTLE_ENDIAN) + clusterBits =3D virReadBufInt32LE(buf + QCOWX_HDR_CLUSTER_BITS_OFF= SET); + else + clusterBits =3D virReadBufInt32BE(buf + QCOWX_HDR_CLUSTER_BITS_OFF= SET); + + if (clusterBits > 0) + return 1 << clusterBits; + + return 0; +} + + static int qcowXGetBackingStore(char **res, int *format, @@ -890,6 +921,11 @@ virStorageFileProbeGetMetadata(virStorageSource *meta, meta->capacity *=3D fileTypeInfo[meta->format].sizeMultiplier; } =20 + if (fileTypeInfo[meta->format].getClusterSize !=3D NULL) { + meta->clusterSize =3D fileTypeInfo[meta->format].getClusterSize(bu= f, len, + file= TypeInfo[meta->format].endian); + } + VIR_FREE(meta->backingStoreRaw); if (fileTypeInfo[meta->format].getBackingStore !=3D NULL) { int store =3D fileTypeInfo[meta->format].getBackingStore(&meta->ba= ckingStoreRaw, --=20 2.31.1