qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 09/14] block-qcow2: keep highest alloc offset in a q


From: Uri Lublin
Subject: [Qemu-devel] [PATCH 09/14] block-qcow2: keep highest alloc offset in a qcow2 extension
Date: Tue, 17 Mar 2009 22:40:47 +0200

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 <address@hidden>
---
 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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]