From patchwork Thu Jun 29 10:57:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Lieven X-Patchwork-Id: 9816437 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9FA846020A for ; Thu, 29 Jun 2017 11:03:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 932502811E for ; Thu, 29 Jun 2017 11:03:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 87BEC28636; Thu, 29 Jun 2017 11:03:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 7AA722811E for ; Thu, 29 Jun 2017 11:03:53 +0000 (UTC) Received: from localhost ([::1]:38336 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dQXEm-0003bU-Pu for patchwork-qemu-devel@patchwork.kernel.org; Thu, 29 Jun 2017 07:03:52 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:51786) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dQX8h-00074z-8Z for qemu-devel@nongnu.org; Thu, 29 Jun 2017 06:57:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dQX8d-000848-PG for qemu-devel@nongnu.org; Thu, 29 Jun 2017 06:57:35 -0400 Received: from mx-v6.kamp.de ([2a02:248:0:51::16]:34450 helo=mx01.kamp.de) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dQX8d-00081f-EV for qemu-devel@nongnu.org; Thu, 29 Jun 2017 06:57:31 -0400 Received: (qmail 9193 invoked by uid 89); 29 Jun 2017 10:57:28 -0000 Received: from [195.62.97.28] by client-16-kamp (envelope-from , uid 89) with qmail-scanner-2010/03/19-MF (clamdscan: 0.99.2/23517. avast: 1.2.2/17010300. spamassassin: 3.4.1. Clear:RC:1(195.62.97.28):. Processed in 0.351141 secs); 29 Jun 2017 10:57:28 -0000 Received: from smtp.kamp.de (HELO submission.kamp.de) ([195.62.97.28]) by mx01.kamp.de with ESMTPS (DHE-RSA-AES256-GCM-SHA384 encrypted); 29 Jun 2017 10:57:25 -0000 X-GL_Whitelist: yes Received: (qmail 12783 invoked from network); 29 Jun 2017 10:57:15 -0000 Received: from lieven-pc.kamp-intra.net (HELO lieven-pc) (relay@kamp.de@::ffff:172.21.12.60) by submission.kamp.de with ESMTPS (DHE-RSA-AES256-GCM-SHA384 encrypted) ESMTPA; 29 Jun 2017 10:57:15 -0000 Received: by lieven-pc (Postfix, from userid 1000) id A9B6126C28; Thu, 29 Jun 2017 12:57:15 +0200 (CEST) From: Peter Lieven To: qemu-block@nongnu.org Date: Thu, 29 Jun 2017 12:57:08 +0200 Message-Id: <1498733831-15254-6-git-send-email-pl@kamp.de> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1498733831-15254-1-git-send-email-pl@kamp.de> References: <1498733831-15254-1-git-send-email-pl@kamp.de> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a02:248:0:51::16 Subject: [Qemu-devel] [PATCH V2 5/8] block/qcow2: read and write the compress format extension X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, Peter Lieven , qemu-devel@nongnu.org, mreitz@redhat.com, den@openvz.org, lersek@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP we now read the extension on open and write it on update, but do not yet use it. Signed-off-by: Peter Lieven --- block/qcow2.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- block/qcow2.h | 23 +++++++++++--- 2 files changed, 104 insertions(+), 19 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 308121a..39a8afc 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -63,6 +63,7 @@ typedef struct { #define QCOW2_EXT_MAGIC_END 0 #define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 +#define QCOW2_EXT_MAGIC_COMPRESS_FORMAT 0xC03183A3 static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) { @@ -76,6 +77,26 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } +static int qcow2_compress_format_from_name(char *fmt) +{ + if (!fmt || !fmt[0]) { + return QCOW2_COMPRESS_ZLIB_COMPAT; + } else if (g_str_equal(fmt, "zlib")) { + return QCOW2_COMPRESS_ZLIB; + } else { + return -EINVAL; + } +} + +static int qcow2_compress_level_supported(int id, uint64_t level) +{ + if ((id == QCOW2_COMPRESS_ZLIB_COMPAT && level > 0) || + (id == QCOW2_COMPRESS_ZLIB && level > 9) || + level > 0xff) { + return -EINVAL; + } + return 0; +} /* * read qcow2 extension and fill bs @@ -148,6 +169,43 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, #endif break; + case QCOW2_EXT_MAGIC_COMPRESS_FORMAT: + if (ext.len != sizeof(s->compress_format)) { + error_setg(errp, "ERROR: ext_compress_format: len=%" + PRIu32 " invalid (!=%zu)", ext.len, + sizeof(s->compress_format)); + return 2; + } + ret = bdrv_pread(bs->file, offset, &s->compress_format, + ext.len); + if (ret < 0) { + error_setg_errno(errp, -ret, "ERROR: ext_compress_fromat:" + " Could not read extension"); + return 3; + } + s->compress_format_id = + qcow2_compress_format_from_name(s->compress_format.name); + if (s->compress_format_id < 0) { + error_setg(errp, "ERROR: compression algorithm '%s' is " + " unsupported", s->compress_format.name); + return 4; + } + if (qcow2_compress_level_supported(s->compress_format_id, + s->compress_format.level) < 0) { + error_setg(errp, "ERROR: compress level %" PRIu8 " is not" + " supported for format '%s'", + s->compress_format.level, s->compress_format.name); + return 5; + } + +#ifdef DEBUG_EXT + printf("Qcow2: Got compress format %s with compress level %" + PRIu8 "\n", s->compress_format.name, + s->compress_format.level); +#endif + break; + + case QCOW2_EXT_MAGIC_FEATURE_TABLE: if (p_feature_table != NULL) { void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature)); @@ -1981,6 +2039,20 @@ int qcow2_update_header(BlockDriverState *bs) buflen -= ret; } + /* Compress Format header extension */ + if (s->compress_format.name[0]) { + assert(!s->compress_format.extra_data_size); + ret = header_ext_add(buf, QCOW2_EXT_MAGIC_COMPRESS_FORMAT, + &s->compress_format, sizeof(s->compress_format), + buflen); + if (ret < 0) { + goto fail; + } + buf += ret; + buflen -= ret; + header->incompatible_features |= cpu_to_be64(QCOW2_INCOMPAT_COMPRESS); + } + /* Feature table */ if (s->qcow_version >= 3) { Qcow2Feature features[] = { @@ -1995,6 +2067,11 @@ int qcow2_update_header(BlockDriverState *bs) .name = "corrupt bit", }, { + .type = QCOW2_FEAT_TYPE_INCOMPATIBLE, + .bit = QCOW2_INCOMPAT_COMPRESS_BITNR, + .name = "compress format bit", + }, + { .type = QCOW2_FEAT_TYPE_COMPATIBLE, .bit = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR, .name = "lazy refcounts", @@ -2333,6 +2410,13 @@ static int qcow2_create2(const char *filename, int64_t total_size, abort(); } + if (compress_format_name[0]) { + BDRVQcow2State *s = blk_bs(blk)->opaque; + memcpy(s->compress_format.name, compress_format_name, + strlen(compress_format_name)); + s->compress_format.level = compress_level; + } + /* Create a full header (including things like feature table) */ ret = qcow2_update_header(blk_bs(blk)); if (ret < 0) { @@ -2391,17 +2475,6 @@ out: return ret; } -static int qcow2_compress_format_from_name(char *fmt) -{ - if (!fmt || !fmt[0]) { - return QCOW2_COMPRESS_ZLIB_COMPAT; - } else if (g_str_equal(fmt, "zlib")) { - return QCOW2_COMPRESS_ZLIB; - } else { - return -EINVAL; - } -} - static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) { char *backing_file = NULL; @@ -2505,11 +2578,10 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) ret = -EINVAL; goto finish; } - if ((ret == QCOW2_COMPRESS_ZLIB && compress_level > 9) || - compress_level > 0xff) { + ret = qcow2_compress_level_supported(ret, compress_level); + if (ret < 0) { error_setg(errp, "Compress level %" PRIu64 " is not supported for" " format '%s'", compress_level, compress_format_name); - ret = -EINVAL; goto finish; } diff --git a/block/qcow2.h b/block/qcow2.h index d21da33..4ceaba1 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -187,13 +187,16 @@ enum { /* Incompatible feature bits */ enum { - QCOW2_INCOMPAT_DIRTY_BITNR = 0, - QCOW2_INCOMPAT_CORRUPT_BITNR = 1, - QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR, - QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, + QCOW2_INCOMPAT_DIRTY_BITNR = 0, + QCOW2_INCOMPAT_CORRUPT_BITNR = 1, + QCOW2_INCOMPAT_COMPRESS_BITNR = 2, + QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR, + QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, + QCOW2_INCOMPAT_COMPRESS = 1 << QCOW2_INCOMPAT_COMPRESS_BITNR, QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY - | QCOW2_INCOMPAT_CORRUPT, + | QCOW2_INCOMPAT_CORRUPT + | QCOW2_INCOMPAT_COMPRESS, }; /* Compatible feature bits */ @@ -219,6 +222,13 @@ typedef struct Qcow2Feature { char name[46]; } QEMU_PACKED Qcow2Feature; +typedef struct Qcow2CompressFormatExt { + char name[16]; + uint8_t level; + char res[3]; + uint32_t extra_data_size; +} QEMU_PACKED Qcow2CompressFormatExt; + typedef struct Qcow2DiscardRegion { BlockDriverState *bs; uint64_t offset; @@ -303,6 +313,9 @@ typedef struct BDRVQcow2State { * override) */ char *image_backing_file; char *image_backing_format; + + Qcow2CompressFormatExt compress_format; + int compress_format_id; } BDRVQcow2State; typedef struct Qcow2COWRegion {