From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Ljg6B-0006T8-Ps for qemu-devel@nongnu.org; Tue, 17 Mar 2009 16:41:19 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Ljg68-0006Ql-6Z for qemu-devel@nongnu.org; Tue, 17 Mar 2009 16:41:19 -0400 Received: from [199.232.76.173] (port=57240 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Ljg67-0006Qb-G5 for qemu-devel@nongnu.org; Tue, 17 Mar 2009 16:41:15 -0400 Received: from mx1.redhat.com ([66.187.233.31]:45040) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Ljg66-0004JZ-SC for qemu-devel@nongnu.org; Tue, 17 Mar 2009 16:41:15 -0400 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id n2HKfEJk020303 for ; Tue, 17 Mar 2009 16:41:14 -0400 From: Uri Lublin Date: Tue, 17 Mar 2009 22:40:47 +0200 Message-Id: <1237322452-11337-10-git-send-email-uril@redhat.com> In-Reply-To: <1237322452-11337-9-git-send-email-uril@redhat.com> References: <1237322452-11337-1-git-send-email-uril@redhat.com> <1237322452-11337-2-git-send-email-uril@redhat.com> <1237322452-11337-3-git-send-email-uril@redhat.com> <1237322452-11337-4-git-send-email-uril@redhat.com> <1237322452-11337-5-git-send-email-uril@redhat.com> <1237322452-11337-6-git-send-email-uril@redhat.com> <1237322452-11337-7-git-send-email-uril@redhat.com> <1237322452-11337-8-git-send-email-uril@redhat.com> <1237322452-11337-9-git-send-email-uril@redhat.com> Subject: [Qemu-devel] [PATCH 09/14] block-qcow2: keep highest alloc offset in a qcow2 extension Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Uri Lublin Write it upon qcow_create. Read it upon qcow_open. Update (if changed and an extension already exists) upon qcow_close. This makes highest allocated offset statistic more accurate. Signed-off-by: Uri Lublin --- block-qcow2.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 96 insertions(+), 5 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index 53364ff..ed84a56 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -85,6 +85,7 @@ typedef struct { } QCowExtension; #define QCOW_EXT_MAGIC_END 0 #define QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA +#define QCOW_EXT_MAGIC_HIGH_ALLOC 0xE2792ACB typedef struct __attribute__((packed)) QCowSnapshotHeader { @@ -155,6 +156,8 @@ typedef struct BDRVQcowState { AES_KEY aes_decrypt_key; int64_t highest_alloc; /* highest cluester allocated (in clusters) */ + int64_t highest_alloc_old; /* highest-alloc value when image opened */ + int64_t highest_alloc_offset; /* offset on disk to highest-alloc value */ uint64_t snapshots_offset; int snapshots_size; @@ -209,7 +212,8 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, BDRVQcowState *s = bs->opaque; QCowExtension ext; uint64_t offset; - + uint64_t high; + #ifdef DEBUG_EXT printf("qcow_read_extensions: start=%ld end=%ld\n", start_offset, end_offset); #endif @@ -256,6 +260,24 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, offset += ((ext.len + 7) & ~7); break; + case QCOW_EXT_MAGIC_HIGH_ALLOC: + if (ext.len != sizeof(uint64_t)) { + fprintf(stderr, "ERROR: ext_high_alloc: len=%u too large" + " (>=%lu)\n", + ext.len, sizeof(uint64_t)); + return 2; + } + if (bdrv_pread(s->hd, offset , &high, ext.len) != ext.len) + return 3; + s->highest_alloc = be64_to_cpu(high); + s->highest_alloc_old = s->highest_alloc; + s->highest_alloc_offset = offset; +#ifdef DEBUG_EXT + printf("Qcow2: Got highest_alloc 0x%lu\n", s->highest_alloc); +#endif + offset += ((ext.len + 7) & ~7); + break; + default: /* unknown magic -- just skip it */ offset += ((ext.len + 7) & ~7); @@ -267,6 +289,62 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, } +static void update_highest_alloc(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + uint64_t high; + int ret; + +#ifdef DEBUG_EXT + QCowExtension ext; + int len; + char buff[32]; + + printf("IN update_highest_alloc for %s: current %lu old %lu offset=%lu\n", + bs->filename, s->highest_alloc, s->highest_alloc_old, + s->highest_alloc_offset); +#endif + + if (s->highest_alloc_offset <= 0) + return; + + if (s->highest_alloc == s->highest_alloc_old) + return; + +#ifdef DEBUG_EXT + printf("Writing highest_alloc=%lu, was %lu\n", + s->highest_alloc, s->highest_alloc_old); + + len = sizeof(ext) + sizeof(uint64_t); + ret = bdrv_pread(s->hd, s->highest_alloc_offset - sizeof(uint64_t), + buff, len); + if (ret != len) + fprintf(stderr, "%s: bdrv_pread FAILED (ret=%d expected %d\n", + __FUNCTION__, ret, len); + if (be32_to_cpu(*(uint32_t*)buff) != QCOW_EXT_MAGIC_HIGH_ALLOC) + fprintf(stderr, "%s: offset points to the wrong location (magic)", + __FUNCTION__); + if (be32_to_cpu(*((uint32_t*)buff + 1)) != sizeof(uint64_t)) + fprintf(stderr, "%s: offset points to the wrong location (len)", + __FUNCTION__); + high = be64_to_cpu(*(uint64_t*)(buff + sizeof(ext))); + if (high != s->highest_alloc_old) + fprintf(stderr, "%s: offset points to the wrong location (value)", + __FUNCTION__); +#endif + + high = cpu_to_be64(s->highest_alloc); + ret = bdrv_pwrite(s->hd, s->highest_alloc_offset, &high, sizeof(uint64_t)); + +#ifdef DEBUG_EXT + if (ret != sizeof(uint64_t)) + fprintf(stderr, "update highest-alloc: bdrv_pwrite FAILED (%d e=%d)\n", + ret, (int)sizeof(uint64_t)); +#endif +} + + + static int qcow_open(BlockDriverState *bs, const char *filename, int flags) { BDRVQcowState *s = bs->opaque; @@ -363,8 +441,6 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) if (qcow_read_extensions(bs, sizeof(header), ext_end)) goto fail; - s->highest_alloc = 0; - /* read the backing file name */ if (header.backing_file_offset != 0) { len = header.backing_file_size; @@ -1509,9 +1585,12 @@ static void qcow_aio_cancel(BlockDriverAIOCB *blockacb) qemu_aio_release(acb); } + static void qcow_close(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; + + update_highest_alloc(bs); qemu_free(s->l1_table); qemu_free(s->l2_cache); qemu_free(s->cluster_cache); @@ -1557,10 +1636,10 @@ static int qcow_create2(const char *filename, int64_t total_size, int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; int backing_format_len = 0; QCowHeader header; - uint64_t tmp, offset; + uint64_t tmp, offset, high_alloc; QCowCreateState s1, *s = &s1; QCowExtension ext_bf = {0, 0}; - + QCowExtension ext_ha = {0, 0}; memset(s, 0, sizeof(*s)); @@ -1572,6 +1651,9 @@ static int qcow_create2(const char *filename, int64_t total_size, header.version = cpu_to_be32(QCOW_VERSION); header.size = cpu_to_be64(total_size * 512); header_size = sizeof(header); + ext_ha.magic = QCOW_EXT_MAGIC_HIGH_ALLOC; + ext_ha.len = sizeof(uint64_t); + header_size += ((sizeof(ext_ha) + ext_ha.len + 7) & ~7); backing_filename_len = 0; if (backing_file) { if (backing_format) { @@ -1623,6 +1705,15 @@ static int qcow_create2(const char *filename, int64_t total_size, /* write all the data */ write(fd, &header, sizeof(header)); + + + cpu_to_be32s(&ext_ha.magic); + cpu_to_be32s(&ext_ha.len); + high_alloc = cpu_to_be64(offset >> s->cluster_bits); + + write(fd, &ext_ha, sizeof(ext_ha)); + write(fd, &high_alloc, sizeof(uint64_t)); + if (backing_file) { if (backing_format_len) { char zero[16]; -- 1.6.0.6