remove compilation warning in omap3_usb.c
[qemu] / block-qcow2.c
index d8ac647..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;
@@ -183,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
@@ -253,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;
@@ -263,21 +344,23 @@ 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;
 
+    /* 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) {
         len = header.backing_file_size;
@@ -451,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) */
@@ -615,7 +696,7 @@ static int size_to_clusters(BDRVQcowState *s, int64_t size)
 }
 
 static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
-        uint64_t *l2_table, uint64_t mask)
+        uint64_t *l2_table, uint64_t start, uint64_t mask)
 {
     int i;
     uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
@@ -623,11 +704,11 @@ static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
     if (!offset)
         return 0;
 
-    for (i = 0; i < nb_clusters; i++)
+    for (i = start; i < start + nb_clusters; i++)
         if (offset + i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
             break;
 
-       return i;
+       return (i - start);
 }
 
 static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
@@ -714,7 +795,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
     } else {
         /* how many allocated clusters ? */
         c = count_contiguous_clusters(nb_clusters, s->cluster_size,
-                &l2_table[l2_index], QCOW_OFLAG_COPIED);
+                &l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
     }
 
    nb_available = (c * s->cluster_sectors);
@@ -885,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;
@@ -968,7 +1048,7 @@ static uint64_t alloc_cluster_offset(BlockDriverState *bs,
 
     if (cluster_offset & QCOW_OFLAG_COPIED) {
         nb_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
-                &l2_table[l2_index], 0);
+                &l2_table[l2_index], 0, 0);
 
         cluster_offset &= ~QCOW_OFLAG_COPIED;
         m->nb_clusters = 0;
@@ -985,7 +1065,7 @@ static uint64_t alloc_cluster_offset(BlockDriverState *bs,
 
     while (i < nb_clusters) {
         i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
-                &l2_table[l2_index + i], 0);
+                &l2_table[l2_index], i, 0);
 
         if(be64_to_cpu(l2_table[l2_index + i]))
             break;
@@ -1385,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);
@@ -1469,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));
 
@@ -1489,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);
@@ -1513,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);
@@ -1537,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);
@@ -1554,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)
@@ -1605,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));
@@ -1689,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)
@@ -1705,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];
@@ -1809,10 +1900,14 @@ static int qcow_read_snapshots(BlockDriverState *bs)
     int64_t offset;
     uint32_t extra_data_size;
 
+    if (!s->nb_snapshots) {
+        s->snapshots = NULL;
+        s->snapshots_size = 0;
+        return 0;
+    }
+
     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))
@@ -1833,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;
@@ -2008,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]);
     }
@@ -2021,9 +2110,10 @@ static int qcow_snapshot_create(BlockDriverState *bs,
     l1_table = NULL;
 
     snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
-    if (!snapshots1)
-        goto fail;
-    memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
+    if (s->snapshots) {
+        memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
+        qemu_free(s->snapshots);
+    }
     s->snapshots = snapshots1;
     s->snapshots[s->nb_snapshots++] = *sn;
 
@@ -2126,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;
@@ -2142,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;
 }
 
 /*********************************************************/
@@ -2157,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);
@@ -2326,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++)
@@ -2492,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;
@@ -2502,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) {
@@ -2638,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,
 };