remove compilation warning in omap3_usb.c
[qemu] / block-qcow2.c
index 8a5b621..60d87a4 100644 (file)
@@ -45,6 +45,7 @@
 
 //#define DEBUG_ALLOC
 //#define DEBUG_ALLOC2
+//#define DEBUG_EXT
 
 #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
 #define QCOW_VERSION 2
@@ -77,6 +78,15 @@ typedef struct QCowHeader {
     uint64_t snapshots_offset;
 } QCowHeader;
 
+
+typedef struct {
+    uint32_t magic;
+    uint32_t len;
+} QCowExtension;
+#define  QCOW_EXT_MAGIC_END 0
+#define  QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
+
+
 typedef struct __attribute__((packed)) QCowSnapshotHeader {
     /* header is 8 byte aligned */
     uint64_t l1_table_offset;
@@ -143,10 +153,6 @@ typedef struct BDRVQcowState {
     uint32_t crypt_method_header;
     AES_KEY aes_encrypt_key;
     AES_KEY aes_decrypt_key;
-
-    int64_t highest_alloc; /* highest cluester allocated (in clusters) */
-    int64_t nc_free;       /* num of free clusters below highest_alloc */
-
     uint64_t snapshots_offset;
     int snapshots_size;
     int nb_snapshots;
@@ -174,8 +180,6 @@ static void free_clusters(BlockDriverState *bs,
 #ifdef DEBUG_ALLOC
 static void check_refcounts(BlockDriverState *bs);
 #endif
-static void scan_refcount(BlockDriverState *bs, int64_t *high, int64_t *free);
-
 
 static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
@@ -189,11 +193,84 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
         return 0;
 }
 
+
+/* 
+ * read qcow2 extension and fill bs
+ * start reading from start_offset
+ * finish reading upon magic of value 0 or when end_offset reached
+ * unknown magic is skipped (future extension this version knows nothing about)
+ * return 0 upon success, non-0 otherwise
+ */
+static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
+                                uint64_t end_offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowExtension ext;
+    uint64_t offset;
+
+#ifdef DEBUG_EXT
+    printf("qcow_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
+#endif
+    offset = start_offset;
+    while (offset < end_offset) {
+
+#ifdef DEBUG_EXT
+        /* Sanity check */
+        if (offset > s->cluster_size)
+            printf("qcow_handle_extension: suspicious offset %lu\n", offset);
+
+        printf("attemting to read extended header in offset %lu\n", offset);
+#endif
+
+        if (bdrv_pread(s->hd, offset, &ext, sizeof(ext)) != sizeof(ext)) {
+            fprintf(stderr, "qcow_handle_extension: ERROR: pread fail from offset %llu\n",
+                    (unsigned long long)offset);
+            return 1;
+        }
+        be32_to_cpus(&ext.magic);
+        be32_to_cpus(&ext.len);
+        offset += sizeof(ext);
+#ifdef DEBUG_EXT
+        printf("ext.magic = 0x%x\n", ext.magic);
+#endif
+        switch (ext.magic) {
+        case QCOW_EXT_MAGIC_END:
+            return 0;
+
+        case QCOW_EXT_MAGIC_BACKING_FORMAT:
+            if (ext.len >= sizeof(bs->backing_format)) {
+                fprintf(stderr, "ERROR: ext_backing_format: len=%u too large"
+                        " (>=%zu)\n",
+                        ext.len, sizeof(bs->backing_format));
+                return 2;
+            }
+            if (bdrv_pread(s->hd, offset , bs->backing_format,
+                           ext.len) != ext.len)
+                return 3;
+            bs->backing_format[ext.len] = '\0';
+#ifdef DEBUG_EXT
+            printf("Qcow2: Got format extension %s\n", bs->backing_format);
+#endif
+            offset += ((ext.len + 7) & ~7);
+            break;
+
+        default:
+            /* unknown magic -- just skip it */
+            offset += ((ext.len + 7) & ~7);
+            break;
+        }
+    }
+
+    return 0;
+}
+
+
 static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVQcowState *s = bs->opaque;
     int len, i, shift, ret;
     QCowHeader header;
+    uint64_t ext_end;
 
     /* Performance is terrible right now with cache=writethrough due mainly
      * to reference count updates.  If the user does not explicitly specify
@@ -259,8 +336,6 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
         goto fail;
     s->l1_table_offset = header.l1_table_offset;
     s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
-    if (!s->l1_table)
-        goto fail;
     if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
         s->l1_size * sizeof(uint64_t))
         goto fail;
@@ -269,22 +344,22 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
     }
     /* alloc L2 cache */
     s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
-    if (!s->l2_cache)
-        goto fail;
     s->cluster_cache = qemu_malloc(s->cluster_size);
-    if (!s->cluster_cache)
-        goto fail;
     /* one more sector for decompressed data alignment */
     s->cluster_data = qemu_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
                                   + 512);
-    if (!s->cluster_data)
-        goto fail;
     s->cluster_cache_offset = -1;
 
     if (refcount_init(bs) < 0)
         goto fail;
 
-    scan_refcount(bs, &s->highest_alloc, &s->nc_free);
+    /* read qcow2 extensions */
+    if (header.backing_file_offset)
+        ext_end = header.backing_file_offset;
+    else
+        ext_end = s->cluster_size;
+    if (qcow_read_extensions(bs, sizeof(header), ext_end))
+        goto fail;
 
     /* read the backing file name */
     if (header.backing_file_offset != 0) {
@@ -459,8 +534,6 @@ static int grow_l1_table(BlockDriverState *bs, int min_size)
 
     new_l1_size2 = sizeof(uint64_t) * new_l1_size;
     new_l1_table = qemu_mallocz(new_l1_size2);
-    if (!new_l1_table)
-        return -ENOMEM;
     memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
 
     /* write new table (align to cluster) */
@@ -893,8 +966,7 @@ static int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
     if (m->nb_clusters == 0)
         return 0;
 
-    if (!(old_cluster = qemu_malloc(m->nb_clusters * sizeof(uint64_t))))
-        return -ENOMEM;
+    old_cluster = qemu_malloc(m->nb_clusters * sizeof(uint64_t));
 
     /* copy content of unmodified sectors */
     start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9;
@@ -1393,10 +1465,6 @@ static void qcow_aio_write_cb(void *opaque, int ret)
         if (!acb->cluster_data) {
             acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
                                              s->cluster_size);
-            if (!acb->cluster_data) {
-                ret = -ENOMEM;
-                goto fail;
-            }
         }
         encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
                         acb->n, 1, &s->aes_encrypt_key);
@@ -1477,13 +1545,18 @@ static void create_refcount_update(QCowCreateState *s,
     }
 }
 
-static int qcow_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
+static int qcow_create2(const char *filename, int64_t total_size,
+                        const char *backing_file, const char *backing_format,
+                        int flags)
 {
+
     int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
+    int backing_format_len = 0;
     QCowHeader header;
     uint64_t tmp, offset;
     QCowCreateState s1, *s = &s1;
+    QCowExtension ext_bf = {0, 0};
+
 
     memset(s, 0, sizeof(*s));
 
@@ -1497,6 +1570,12 @@ static int qcow_create(const char *filename, int64_t total_size,
     header_size = sizeof(header);
     backing_filename_len = 0;
     if (backing_file) {
+        if (backing_format) {
+            ext_bf.magic = QCOW_EXT_MAGIC_BACKING_FORMAT;
+            backing_format_len = strlen(backing_format);
+            ext_bf.len = (backing_format_len + 7) & ~7;
+            header_size += ((sizeof(ext_bf) + ext_bf.len + 7) & ~7);
+        }
         header.backing_file_offset = cpu_to_be64(header_size);
         backing_filename_len = strlen(backing_file);
         header.backing_file_size = cpu_to_be32(backing_filename_len);
@@ -1521,11 +1600,7 @@ static int qcow_create(const char *filename, int64_t total_size,
     offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
 
     s->refcount_table = qemu_mallocz(s->cluster_size);
-    if (!s->refcount_table)
-        goto fail;
     s->refcount_block = qemu_mallocz(s->cluster_size);
-    if (!s->refcount_block)
-        goto fail;
 
     s->refcount_table_offset = offset;
     header.refcount_table_offset = cpu_to_be64(offset);
@@ -1545,6 +1620,19 @@ static int qcow_create(const char *filename, int64_t total_size,
     /* write all the data */
     write(fd, &header, sizeof(header));
     if (backing_file) {
+        if (backing_format_len) {
+            char zero[16];
+            int d = ext_bf.len - backing_format_len;
+
+            memset(zero, 0, sizeof(zero));
+            cpu_to_be32s(&ext_bf.magic);
+            cpu_to_be32s(&ext_bf.len);
+            write(fd, &ext_bf, sizeof(ext_bf));
+            write(fd, backing_format, backing_format_len);
+            if (d>0) {
+                write(fd, zero, d);
+            }
+        }
         write(fd, backing_file, backing_filename_len);
     }
     lseek(fd, s->l1_table_offset, SEEK_SET);
@@ -1562,11 +1650,12 @@ static int qcow_create(const char *filename, int64_t total_size,
     qemu_free(s->refcount_block);
     close(fd);
     return 0;
- fail:
-    qemu_free(s->refcount_table);
-    qemu_free(s->refcount_block);
-    close(fd);
-    return -ENOMEM;
+}
+
+static int qcow_create(const char *filename, int64_t total_size,
+                       const char *backing_file, int flags)
+{
+    return qcow_create2(filename, total_size, backing_file, NULL, flags);
 }
 
 static int qcow_make_empty(BlockDriverState *bs)
@@ -1613,8 +1702,6 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
         return -EINVAL;
 
     out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
-    if (!out_buf)
-        return -ENOMEM;
 
     /* best compression, small window, no zlib header */
     memset(&strm, 0, sizeof(strm));
@@ -1672,8 +1759,6 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
     bdi->cluster_size = s->cluster_size;
     bdi->vm_state_offset = (int64_t)s->l1_vm_state_index <<
         (s->cluster_bits + s->l2_bits);
-    bdi->highest_alloc = s->highest_alloc << s->cluster_bits;
-    bdi->num_free_bytes = s->nc_free  << s->cluster_bits;
     return 0;
 }
 
@@ -1699,8 +1784,6 @@ static int update_snapshot_refcount(BlockDriverState *bs,
     l1_allocated = 0;
     if (l1_table_offset != s->l1_table_offset) {
         l1_table = qemu_malloc(l1_size2);
-        if (!l1_table)
-            goto fail;
         l1_allocated = 1;
         if (bdrv_pread(s->hd, l1_table_offset,
                        l1_table, l1_size2) != l1_size2)
@@ -1715,8 +1798,6 @@ static int update_snapshot_refcount(BlockDriverState *bs,
 
     l2_size = s->l2_size * sizeof(uint64_t);
     l2_table = qemu_malloc(l2_size);
-    if (!l2_table)
-        goto fail;
     l1_modified = 0;
     for(i = 0; i < l1_size; i++) {
         l2_offset = l1_table[i];
@@ -1827,8 +1908,6 @@ static int qcow_read_snapshots(BlockDriverState *bs)
 
     offset = s->snapshots_offset;
     s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
-    if (!s->snapshots)
-        goto fail;
     for(i = 0; i < s->nb_snapshots; i++) {
         offset = align_offset(offset, 8);
         if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
@@ -1849,16 +1928,12 @@ static int qcow_read_snapshots(BlockDriverState *bs)
         offset += extra_data_size;
 
         sn->id_str = qemu_malloc(id_str_size + 1);
-        if (!sn->id_str)
-            goto fail;
         if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
             goto fail;
         offset += id_str_size;
         sn->id_str[id_str_size] = '\0';
 
         sn->name = qemu_malloc(name_size + 1);
-        if (!sn->name)
-            goto fail;
         if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
             goto fail;
         offset += name_size;
@@ -2024,8 +2099,6 @@ static int qcow_snapshot_create(BlockDriverState *bs,
     sn->l1_size = s->l1_size;
 
     l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
-    if (!l1_table)
-        goto fail;
     for(i = 0; i < s->l1_size; i++) {
         l1_table[i] = cpu_to_be64(s->l1_table[i]);
     }
@@ -2037,8 +2110,6 @@ static int qcow_snapshot_create(BlockDriverState *bs,
     l1_table = NULL;
 
     snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
-    if (!snapshots1)
-        goto fail;
     if (s->snapshots) {
         memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
         qemu_free(s->snapshots);
@@ -2145,8 +2216,6 @@ static int qcow_snapshot_list(BlockDriverState *bs,
     int i;
 
     sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
-    if (!sn_tab)
-        goto fail;
     for(i = 0; i < s->nb_snapshots; i++) {
         sn_info = sn_tab + i;
         sn = s->snapshots + i;
@@ -2161,10 +2230,6 @@ static int qcow_snapshot_list(BlockDriverState *bs,
     }
     *psn_tab = sn_tab;
     return s->nb_snapshots;
- fail:
-    qemu_free(sn_tab);
-    *psn_tab = NULL;
-    return -ENOMEM;
 }
 
 /*********************************************************/
@@ -2176,12 +2241,8 @@ static int refcount_init(BlockDriverState *bs)
     int ret, refcount_table_size2, i;
 
     s->refcount_block_cache = qemu_malloc(s->cluster_size);
-    if (!s->refcount_block_cache)
-        goto fail;
     refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
     s->refcount_table = qemu_malloc(refcount_table_size2);
-    if (!s->refcount_table)
-        goto fail;
     if (s->refcount_table_size > 0) {
         ret = bdrv_pread(s->hd, s->refcount_table_offset,
                          s->refcount_table, refcount_table_size2);
@@ -2216,39 +2277,6 @@ static int load_refcount_block(BlockDriverState *bs,
     return 0;
 }
 
-static void scan_refcount(BlockDriverState *bs, int64_t *high, int64_t *free)
-{
-    BDRVQcowState *s = bs->opaque;
-    int64_t refcnt_index, cluster_index, cluster_end, h = 0, f = 0;
-    int64_t tail = 0; /* do not count last consecutive free entries */
-
-    for (refcnt_index=0; refcnt_index < s->refcount_table_size; refcnt_index++){
-        if (s->refcount_table[refcnt_index] == 0) {
-            f += 1 << (s->cluster_bits - REFCOUNT_SHIFT);
-            tail += 1 << (s->cluster_bits - REFCOUNT_SHIFT);
-            continue;
-        }
-        cluster_index = refcnt_index << (s->cluster_bits - REFCOUNT_SHIFT);
-        cluster_end = (refcnt_index + 1) << (s->cluster_bits - REFCOUNT_SHIFT);
-        for ( ; cluster_index < cluster_end; cluster_index++) {
-            if (get_refcount(bs, cluster_index) == 0) {
-                f++;
-                tail++;
-            }
-            else {
-                h = cluster_index;
-                tail = 0;
-            }
-        }
-    }
-
-    f -= tail;
-    if (free)
-        *free = f;
-    if (high)
-        *high = (h+1);
-}
-
 static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
 {
     BDRVQcowState *s = bs->opaque;
@@ -2289,12 +2317,6 @@ retry:
             size,
             (s->free_cluster_index - nb_clusters) << s->cluster_bits);
 #endif
-
-    if (s->highest_alloc < s->free_cluster_index) {
-        s->nc_free += (s->free_cluster_index - s->highest_alloc);
-        s->highest_alloc = s->free_cluster_index;
-    }
-
     return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
 }
 
@@ -2384,8 +2406,6 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size)
 #endif
     new_table_size2 = new_table_size * sizeof(uint64_t);
     new_table = qemu_mallocz(new_table_size2);
-    if (!new_table)
-        return -ENOMEM;
     memcpy(new_table, s->refcount_table,
            s->refcount_table_size * sizeof(uint64_t));
     for(i = 0; i < s->refcount_table_size; i++)
@@ -2470,12 +2490,6 @@ static int update_cluster_refcount(BlockDriverState *bs,
     block_index = cluster_index &
         ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
     refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
-
-    if (refcount == 1 && addend == -1)
-        s->nc_free += 1;
-    else if (refcount == 0 && addend == 1)
-        s->nc_free -= 1;
-
     refcount += addend;
     if (refcount < 0 || refcount > 0xffff)
         return -EINVAL;
@@ -2556,8 +2570,6 @@ static int check_refcounts_l1(BlockDriverState *bs,
                   l1_table_offset, l1_size2);
 
     l1_table = qemu_malloc(l1_size2);
-    if (!l1_table)
-        goto fail;
     if (bdrv_pread(s->hd, l1_table_offset,
                    l1_table, l1_size2) != l1_size2)
         goto fail;
@@ -2566,8 +2578,6 @@ static int check_refcounts_l1(BlockDriverState *bs,
 
     l2_size = s->l2_size * sizeof(uint64_t);
     l2_table = qemu_malloc(l2_size);
-    if (!l2_table)
-        goto fail;
     for(i = 0; i < l1_size; i++) {
         l2_offset = l1_table[i];
         if (l2_offset) {
@@ -2702,28 +2712,28 @@ static void dump_refcounts(BlockDriverState *bs)
 #endif
 
 BlockDriver bdrv_qcow2 = {
-    "qcow2",
-    sizeof(BDRVQcowState),
-    qcow_probe,
-    qcow_open,
-    NULL,
-    NULL,
-    qcow_close,
-    qcow_create,
-    qcow_flush,
-    qcow_is_allocated,
-    qcow_set_key,
-    qcow_make_empty,
-
-    .bdrv_aio_read = qcow_aio_read,
-    .bdrv_aio_write = qcow_aio_write,
-    .bdrv_aio_cancel = qcow_aio_cancel,
-    .aiocb_size = sizeof(QCowAIOCB),
+    .format_name       = "qcow2",
+    .instance_size     = sizeof(BDRVQcowState),
+    .bdrv_probe                = qcow_probe,
+    .bdrv_open         = qcow_open,
+    .bdrv_close                = qcow_close,
+    .bdrv_create       = qcow_create,
+    .bdrv_flush                = qcow_flush,
+    .bdrv_is_allocated = qcow_is_allocated,
+    .bdrv_set_key      = qcow_set_key,
+    .bdrv_make_empty   = qcow_make_empty,
+
+    .bdrv_aio_read     = qcow_aio_read,
+    .bdrv_aio_write    = qcow_aio_write,
+    .bdrv_aio_cancel   = qcow_aio_cancel,
+    .aiocb_size                = sizeof(QCowAIOCB),
     .bdrv_write_compressed = qcow_write_compressed,
 
     .bdrv_snapshot_create = qcow_snapshot_create,
-    .bdrv_snapshot_goto = qcow_snapshot_goto,
+    .bdrv_snapshot_goto        = qcow_snapshot_goto,
     .bdrv_snapshot_delete = qcow_snapshot_delete,
-    .bdrv_snapshot_list = qcow_snapshot_list,
-    .bdrv_get_info = qcow_get_info,
+    .bdrv_snapshot_list        = qcow_snapshot_list,
+    .bdrv_get_info     = qcow_get_info,
+
+    .bdrv_create2 = qcow_create2,
 };