Merge remote-tracking branch 'kwolf/for-anthony' into staging
authorAnthony Liguori <aliguori@us.ibm.com>
Fri, 22 Jul 2011 14:23:43 +0000 (09:23 -0500)
committerAnthony Liguori <aliguori@us.ibm.com>
Fri, 22 Jul 2011 14:23:43 +0000 (09:23 -0500)
28 files changed:
block.c
block.h
block/qcow2-cache.c
block/qcow2-refcount.c
block/qcow2.h
block/raw-posix.c
block/raw-win32.c
block/sheepdog.c
block/vmdk.c
block_int.h
hw/esp.c
hw/lsi53c895a.c
hw/scsi-bus.c
hw/scsi-disk.c
hw/scsi-generic.c
hw/scsi.h
hw/spapr_vscsi.c
hw/usb-msd.c
hw/virtio-net.c
hw/virtio-serial-bus.c
iov.c
iov.h
qemu-config.c
qemu-img-cmds.hx
qemu-img.c
qemu-img.texi
qemu-io.c
qemu-options.hx

diff --git a/block.c b/block.c
index 24a25d569be8149f10b153e4fdbbc7c21b1c2f21..9549b9eff9f3034fdfae86e239851db459b9c0da 100644 (file)
--- a/block.c
+++ b/block.c
@@ -1146,6 +1146,25 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
     return ret;
 }
 
+/**
+ * Length of a allocated file in bytes. Sparse files are counted by actual
+ * allocated space. Return < 0 if error or unknown.
+ */
+int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv) {
+        return -ENOMEDIUM;
+    }
+    if (drv->bdrv_get_allocated_file_size) {
+        return drv->bdrv_get_allocated_file_size(bs);
+    }
+    if (bs->file) {
+        return bdrv_get_allocated_file_size(bs->file);
+    }
+    return -ENOTSUP;
+}
+
 /**
  * Length of a file in bytes. Return < 0 if error or unknown.
  */
diff --git a/block.h b/block.h
index 859d1d9835ce45151b8470a36723e4d6d5d7bb21..59cc410e3b1915b2944445824cbabe4cc22f96fd 100644 (file)
--- a/block.h
+++ b/block.h
@@ -89,6 +89,7 @@ int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
     const uint8_t *buf, int nb_sectors);
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
+int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
 void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
 void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
 int bdrv_commit(BlockDriverState *bs);
index 382473933c8490111e6066aff3b89c938955061b..84088477a4298a6611c7ed1e02c29a6a2c500a56 100644 (file)
@@ -312,3 +312,15 @@ found:
     c->entries[i].dirty = true;
 }
 
+bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
+    bool enable)
+{
+    bool old = c->writethrough;
+
+    if (!old && enable) {
+        qcow2_cache_flush(bs, c);
+    }
+
+    c->writethrough = enable;
+    return old;
+}
index ac95b88fe17281f2ba35cd0a747ddd1aa811eebd..14b2f67f14e0d57abb4f0b082feb7cb7fa5882da 100644 (file)
@@ -705,8 +705,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     BDRVQcowState *s = bs->opaque;
     uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
     int64_t old_offset, old_l2_offset;
-    int i, j, l1_modified, nb_csectors, refcount;
+    int i, j, l1_modified = 0, nb_csectors, refcount;
     int ret;
+    bool old_l2_writethrough, old_refcount_writethrough;
+
+    /* Switch caches to writeback mode during update */
+    old_l2_writethrough =
+        qcow2_cache_set_writethrough(bs, s->l2_table_cache, false);
+    old_refcount_writethrough =
+        qcow2_cache_set_writethrough(bs, s->refcount_block_cache, false);
 
     l2_table = NULL;
     l1_table = NULL;
@@ -720,7 +727,11 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
         l1_allocated = 1;
         if (bdrv_pread(bs->file, l1_table_offset,
                        l1_table, l1_size2) != l1_size2)
+        {
+            ret = -EIO;
             goto fail;
+        }
+
         for(i = 0;i < l1_size; i++)
             be64_to_cpus(&l1_table[i]);
     } else {
@@ -729,7 +740,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
         l1_allocated = 0;
     }
 
-    l1_modified = 0;
     for(i = 0; i < l1_size; i++) {
         l2_offset = l1_table[i];
         if (l2_offset) {
@@ -773,6 +783,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                         }
 
                         if (refcount < 0) {
+                            ret = -EIO;
                             goto fail;
                         }
                     }
@@ -803,6 +814,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                 refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
             }
             if (refcount < 0) {
+                ret = -EIO;
                 goto fail;
             } else if (refcount == 1) {
                 l2_offset |= QCOW_OFLAG_COPIED;
@@ -813,6 +825,18 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
             }
         }
     }
+
+    ret = 0;
+fail:
+    if (l2_table) {
+        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    }
+
+    /* Enable writethrough cache mode again */
+    qcow2_cache_set_writethrough(bs, s->l2_table_cache, old_l2_writethrough);
+    qcow2_cache_set_writethrough(bs, s->refcount_block_cache,
+        old_refcount_writethrough);
+
     if (l1_modified) {
         for(i = 0; i < l1_size; i++)
             cpu_to_be64s(&l1_table[i]);
@@ -824,15 +848,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     }
     if (l1_allocated)
         qemu_free(l1_table);
-    return 0;
- fail:
-    if (l2_table) {
-        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
-    }
-
-    if (l1_allocated)
-        qemu_free(l1_table);
-    return -EIO;
+    return ret;
 }
 
 
index e1ae3e8c2b6477df3fcd7ecd107d7d2a59d4cfa5..6a0a21b69443cc49252ea65dea7ee29f8251b83e 100644 (file)
@@ -228,6 +228,8 @@ int qcow2_read_snapshots(BlockDriverState *bs);
 Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
     bool writethrough);
 int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
+bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
+    bool enable);
 
 void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
 int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
index 34b64aa205801081323cd3e6686bcdccd220e7ab..cd89c8312af1d8c7b4f71777bbc73cb720e161f3 100644 (file)
@@ -793,6 +793,17 @@ static int64_t raw_getlength(BlockDriverState *bs)
 }
 #endif
 
+static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
+{
+    struct stat st;
+    BDRVRawState *s = bs->opaque;
+
+    if (fstat(s->fd, &st) < 0) {
+        return -errno;
+    }
+    return (int64_t)st.st_blocks * 512;
+}
+
 static int raw_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
@@ -888,6 +899,8 @@ static BlockDriver bdrv_file = {
 
     .bdrv_truncate = raw_truncate,
     .bdrv_getlength = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     .create_options = raw_create_options,
 };
@@ -1156,6 +1169,8 @@ static BlockDriver bdrv_host_device = {
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
     .bdrv_getlength    = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     /* generic scsi device */
 #ifdef __linux__
@@ -1277,6 +1292,8 @@ static BlockDriver bdrv_host_floppy = {
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
     .bdrv_getlength    = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     /* removable device support */
     .bdrv_is_inserted   = floppy_is_inserted,
@@ -1380,6 +1397,8 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
     .bdrv_getlength     = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     /* removable device support */
     .bdrv_is_inserted   = cdrom_is_inserted,
@@ -1503,6 +1522,8 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
     .bdrv_getlength     = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     /* removable device support */
     .bdrv_is_inserted   = cdrom_is_inserted,
index 56bd7195a1b69906380ffa0aafeba7632037537d..91067e75954c13402bc70b2cc88454b8d84168b9 100644 (file)
@@ -213,6 +213,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
     return l.QuadPart;
 }
 
+static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
+{
+    typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
+                                              DWORD * high);
+    get_compressed_t get_compressed;
+    struct _stati64 st;
+    const char *filename = bs->filename;
+    /* WinNT support GetCompressedFileSize to determine allocate size */
+    get_compressed =
+        (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
+                                            "GetCompressedFileSizeA");
+    if (get_compressed) {
+        DWORD high, low;
+        low = get_compressed(filename, &high);
+        if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
+            return (((int64_t) high) << 32) + low;
+        }
+    }
+
+    if (_stati64(filename, &st) < 0) {
+        return -1;
+    }
+    return st.st_size;
+}
+
 static int raw_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
@@ -257,6 +282,8 @@ static BlockDriver bdrv_file = {
     .bdrv_write                = raw_write,
     .bdrv_truncate     = raw_truncate,
     .bdrv_getlength    = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     .create_options = raw_create_options,
 };
@@ -419,6 +446,8 @@ static BlockDriver bdrv_host_device = {
     .bdrv_read         = raw_read,
     .bdrv_write                = raw_write,
     .bdrv_getlength    = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 };
 
 static void bdrv_file_init(void)
index 80d106c2b22ac4e6bc6ff5df4cf5e80e9ad736d9..77a4de5100c5d393618eea079c7efc862802e561 100644 (file)
@@ -1286,6 +1286,49 @@ static int do_sd_create(char *filename, int64_t vdi_size,
     return 0;
 }
 
+static int sd_prealloc(const char *filename)
+{
+    BlockDriverState *bs = NULL;
+    uint32_t idx, max_idx;
+    int64_t vdi_size;
+    void *buf = qemu_mallocz(SD_DATA_OBJ_SIZE);
+    int ret;
+
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
+    if (ret < 0) {
+        goto out;
+    }
+
+    vdi_size = bdrv_getlength(bs);
+    if (vdi_size < 0) {
+        ret = vdi_size;
+        goto out;
+    }
+    max_idx = DIV_ROUND_UP(vdi_size, SD_DATA_OBJ_SIZE);
+
+    for (idx = 0; idx < max_idx; idx++) {
+        /*
+         * The created image can be a cloned image, so we need to read
+         * a data from the source image.
+         */
+        ret = bdrv_pread(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+        if (ret < 0) {
+            goto out;
+        }
+        ret = bdrv_pwrite(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+        if (ret < 0) {
+            goto out;
+        }
+    }
+out:
+    if (bs) {
+        bdrv_delete(bs);
+    }
+    qemu_free(buf);
+
+    return ret;
+}
+
 static int sd_create(const char *filename, QEMUOptionParameter *options)
 {
     int ret;
@@ -1295,13 +1338,15 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
     BDRVSheepdogState s;
     char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
     uint32_t snapid;
+    int prealloc = 0;
+    const char *vdiname;
 
-    strstart(filename, "sheepdog:", (const char **)&filename);
+    strstart(filename, "sheepdog:", &vdiname);
 
     memset(&s, 0, sizeof(s));
     memset(vdi, 0, sizeof(vdi));
     memset(tag, 0, sizeof(tag));
-    if (parse_vdiname(&s, filename, vdi, &snapid, tag) < 0) {
+    if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) {
         error_report("invalid filename");
         return -EINVAL;
     }
@@ -1311,6 +1356,16 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
             vdi_size = options->value.n;
         } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
             backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
+            if (!options->value.s || !strcmp(options->value.s, "off")) {
+                prealloc = 0;
+            } else if (!strcmp(options->value.s, "full")) {
+                prealloc = 1;
+            } else {
+                error_report("Invalid preallocation mode: '%s'",
+                             options->value.s);
+                return -EINVAL;
+            }
         }
         options++;
     }
@@ -1348,7 +1403,12 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
         bdrv_delete(bs);
     }
 
-    return do_sd_create((char *)vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
+    ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
+    if (!prealloc || ret) {
+        return ret;
+    }
+
+    return sd_prealloc(filename);
 }
 
 static void sd_close(BlockDriverState *bs)
@@ -1984,6 +2044,11 @@ static QEMUOptionParameter sd_create_options[] = {
         .type = OPT_STRING,
         .help = "File name of a base image"
     },
+    {
+        .name = BLOCK_OPT_PREALLOC,
+        .type = OPT_STRING,
+        .help = "Preallocation mode (allowed values: off, full)"
+    },
     { NULL }
 };
 
index 922b23d8f59fb83d7d08ff2b8603a959fdb2130c..37478d2553d02cc1db65ac8f0150cf1d213362b0 100644 (file)
@@ -60,7 +60,12 @@ typedef struct {
 
 #define L2_CACHE_SIZE 16
 
-typedef struct BDRVVmdkState {
+typedef struct VmdkExtent {
+    BlockDriverState *file;
+    bool flat;
+    int64_t sectors;
+    int64_t end_sector;
+    int64_t flat_start_offset;
     int64_t l1_table_offset;
     int64_t l1_backup_table_offset;
     uint32_t *l1_table;
@@ -74,7 +79,15 @@ typedef struct BDRVVmdkState {
     uint32_t l2_cache_counts[L2_CACHE_SIZE];
 
     unsigned int cluster_sectors;
+} VmdkExtent;
+
+typedef struct BDRVVmdkState {
+    int desc_offset;
+    bool cid_updated;
     uint32_t parent_cid;
+    int num_extents;
+    /* Extent array with num_extents entries, ascend ordered by address */
+    VmdkExtent *extents;
 } BDRVVmdkState;
 
 typedef struct VmdkMetaData {
@@ -89,21 +102,77 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     uint32_t magic;
 
-    if (buf_size < 4)
+    if (buf_size < 4) {
         return 0;
+    }
     magic = be32_to_cpu(*(uint32_t *)buf);
     if (magic == VMDK3_MAGIC ||
-        magic == VMDK4_MAGIC)
+        magic == VMDK4_MAGIC) {
         return 100;
-    else
+    } else {
+        const char *p = (const char *)buf;
+        const char *end = p + buf_size;
+        while (p < end) {
+            if (*p == '#') {
+                /* skip comment line */
+                while (p < end && *p != '\n') {
+                    p++;
+                }
+                p++;
+                continue;
+            }
+            if (*p == ' ') {
+                while (p < end && *p == ' ') {
+                    p++;
+                }
+                /* skip '\r' if windows line endings used. */
+                if (p < end && *p == '\r') {
+                    p++;
+                }
+                /* only accept blank lines before 'version=' line */
+                if (p == end || *p != '\n') {
+                    return 0;
+                }
+                p++;
+                continue;
+            }
+            if (end - p >= strlen("version=X\n")) {
+                if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 ||
+                    strncmp("version=2\n", p, strlen("version=2\n")) == 0) {
+                    return 100;
+                }
+            }
+            if (end - p >= strlen("version=X\r\n")) {
+                if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 ||
+                    strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) {
+                    return 100;
+                }
+            }
+            return 0;
+        }
         return 0;
+    }
 }
 
 #define CHECK_CID 1
 
 #define SECTOR_SIZE 512
-#define DESC_SIZE 20*SECTOR_SIZE       // 20 sectors of 512 bytes each
-#define HEADER_SIZE 512                        // first sector of 512 bytes
+#define DESC_SIZE (20 * SECTOR_SIZE)    /* 20 sectors of 512 bytes each */
+#define BUF_SIZE 4096
+#define HEADER_SIZE 512                 /* first sector of 512 bytes */
+
+static void vmdk_free_extents(BlockDriverState *bs)
+{
+    int i;
+    BDRVVmdkState *s = bs->opaque;
+
+    for (i = 0; i < s->num_extents; i++) {
+        qemu_free(s->extents[i].l1_table);
+        qemu_free(s->extents[i].l2_cache);
+        qemu_free(s->extents[i].l1_backup_table);
+    }
+    qemu_free(s->extents);
+}
 
 static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
 {
@@ -111,10 +180,11 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
     uint32_t cid;
     const char *p_name, *cid_str;
     size_t cid_str_size;
+    BDRVVmdkState *s = bs->opaque;
 
-    /* the descriptor offset = 0x200 */
-    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
         return 0;
+    }
 
     if (parent) {
         cid_str = "parentCID";
@@ -124,9 +194,10 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
         cid_str_size = sizeof("CID");
     }
 
-    if ((p_name = strstr(desc,cid_str)) != NULL) {
+    p_name = strstr(desc, cid_str);
+    if (p_name != NULL) {
         p_name += cid_str_size;
-        sscanf(p_name,"%x",&cid);
+        sscanf(p_name, "%x", &cid);
     }
 
     return cid;
@@ -136,21 +207,25 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
 {
     char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
     char *p_name, *tmp_str;
+    BDRVVmdkState *s = bs->opaque;
 
-    /* the descriptor offset = 0x200 */
-    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
-        return -1;
+    memset(desc, 0, sizeof(desc));
+    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
+        return -EIO;
+    }
 
-    tmp_str = strstr(desc,"parentCID");
+    tmp_str = strstr(desc, "parentCID");
     pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
-    if ((p_name = strstr(desc,"CID")) != NULL) {
+    p_name = strstr(desc, "CID");
+    if (p_name != NULL) {
         p_name += sizeof("CID");
         snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
         pstrcat(desc, sizeof(desc), tmp_desc);
     }
 
-    if (bdrv_pwrite_sync(bs->file, 0x200, desc, DESC_SIZE) < 0)
-        return -1;
+    if (bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE) < 0) {
+        return -EIO;
+    }
     return 0;
 }
 
@@ -162,302 +237,387 @@ static int vmdk_is_cid_valid(BlockDriverState *bs)
     uint32_t cur_pcid;
 
     if (p_bs) {
-        cur_pcid = vmdk_read_cid(p_bs,0);
-        if (s->parent_cid != cur_pcid)
-            // CID not valid
+        cur_pcid = vmdk_read_cid(p_bs, 0);
+        if (s->parent_cid != cur_pcid) {
+            /* CID not valid */
             return 0;
+        }
     }
 #endif
-    // CID valid
+    /* CID valid */
     return 1;
 }
 
-static int vmdk_snapshot_create(const char *filename, const char *backing_file)
+static int vmdk_parent_open(BlockDriverState *bs)
 {
-    int snp_fd, p_fd;
-    int ret;
-    uint32_t p_cid;
-    char *p_name, *gd_buf, *rgd_buf;
-    const char *real_filename, *temp_str;
-    VMDK4Header header;
-    uint32_t gde_entries, gd_size;
-    int64_t gd_offset, rgd_offset, capacity, gt_size;
-    char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
-    static const char desc_template[] =
-    "# Disk DescriptorFile\n"
-    "version=1\n"
-    "CID=%x\n"
-    "parentCID=%x\n"
-    "createType=\"monolithicSparse\"\n"
-    "parentFileNameHint=\"%s\"\n"
-    "\n"
-    "# Extent description\n"
-    "RW %u SPARSE \"%s\"\n"
-    "\n"
-    "# The Disk Data Base \n"
-    "#DDB\n"
-    "\n";
-
-    snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
-    if (snp_fd < 0)
-        return -errno;
-    p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
-    if (p_fd < 0) {
-        close(snp_fd);
-        return -errno;
-    }
+    char *p_name;
+    char desc[DESC_SIZE + 1];
+    BDRVVmdkState *s = bs->opaque;
 
-    /* read the header */
-    if (lseek(p_fd, 0x0, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail;
-    }
-    if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) {
-        ret = -errno;
-        goto fail;
+    desc[DESC_SIZE] = '\0';
+    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
+        return -1;
     }
 
-    /* write the header */
-    if (lseek(snp_fd, 0x0, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail;
-    }
-    if (write(snp_fd, hdr, HEADER_SIZE) == -1) {
-        ret = -errno;
-        goto fail;
+    p_name = strstr(desc, "parentFileNameHint");
+    if (p_name != NULL) {
+        char *end_name;
+
+        p_name += sizeof("parentFileNameHint") + 1;
+        end_name = strchr(p_name, '\"');
+        if (end_name == NULL) {
+            return -1;
+        }
+        if ((end_name - p_name) > sizeof(bs->backing_file) - 1) {
+            return -1;
+        }
+
+        pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
     }
 
-    memset(&header, 0, sizeof(header));
-    memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
+    return 0;
+}
 
-    if (ftruncate(snp_fd, header.grain_offset << 9)) {
-        ret = -errno;
-        goto fail;
+/* Create and append extent to the extent array. Return the added VmdkExtent
+ * address. return NULL if allocation failed. */
+static VmdkExtent *vmdk_add_extent(BlockDriverState *bs,
+                           BlockDriverState *file, bool flat, int64_t sectors,
+                           int64_t l1_offset, int64_t l1_backup_offset,
+                           uint32_t l1_size,
+                           int l2_size, unsigned int cluster_sectors)
+{
+    VmdkExtent *extent;
+    BDRVVmdkState *s = bs->opaque;
+
+    s->extents = qemu_realloc(s->extents,
+                              (s->num_extents + 1) * sizeof(VmdkExtent));
+    extent = &s->extents[s->num_extents];
+    s->num_extents++;
+
+    memset(extent, 0, sizeof(VmdkExtent));
+    extent->file = file;
+    extent->flat = flat;
+    extent->sectors = sectors;
+    extent->l1_table_offset = l1_offset;
+    extent->l1_backup_table_offset = l1_backup_offset;
+    extent->l1_size = l1_size;
+    extent->l1_entry_sectors = l2_size * cluster_sectors;
+    extent->l2_size = l2_size;
+    extent->cluster_sectors = cluster_sectors;
+
+    if (s->num_extents > 1) {
+        extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
+    } else {
+        extent->end_sector = extent->sectors;
     }
-    /* the descriptor offset = 0x200 */
-    if (lseek(p_fd, 0x200, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail;
+    bs->total_sectors = extent->end_sector;
+    return extent;
+}
+
+static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
+{
+    int ret;
+    int l1_size, i;
+
+    /* read the L1 table */
+    l1_size = extent->l1_size * sizeof(uint32_t);
+    extent->l1_table = qemu_malloc(l1_size);
+    ret = bdrv_pread(extent->file,
+                    extent->l1_table_offset,
+                    extent->l1_table,
+                    l1_size);
+    if (ret < 0) {
+        goto fail_l1;
     }
-    if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) {
-        ret = -errno;
-        goto fail;
+    for (i = 0; i < extent->l1_size; i++) {
+        le32_to_cpus(&extent->l1_table[i]);
     }
 
-    if ((p_name = strstr(p_desc,"CID")) != NULL) {
-        p_name += sizeof("CID");
-        sscanf(p_name,"%x",&p_cid);
+    if (extent->l1_backup_table_offset) {
+        extent->l1_backup_table = qemu_malloc(l1_size);
+        ret = bdrv_pread(extent->file,
+                        extent->l1_backup_table_offset,
+                        extent->l1_backup_table,
+                        l1_size);
+        if (ret < 0) {
+            goto fail_l1b;
+        }
+        for (i = 0; i < extent->l1_size; i++) {
+            le32_to_cpus(&extent->l1_backup_table[i]);
+        }
     }
 
-    real_filename = filename;
-    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
-        real_filename = temp_str + 1;
-    if ((temp_str = strrchr(real_filename, '/')) != NULL)
-        real_filename = temp_str + 1;
-    if ((temp_str = strrchr(real_filename, ':')) != NULL)
-        real_filename = temp_str + 1;
+    extent->l2_cache =
+        qemu_malloc(extent->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
+    return 0;
+ fail_l1b:
+    qemu_free(extent->l1_backup_table);
+ fail_l1:
+    qemu_free(extent->l1_table);
+    return ret;
+}
 
-    snprintf(s_desc, sizeof(s_desc), desc_template, p_cid, p_cid, backing_file,
-             (uint32_t)header.capacity, real_filename);
+static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
+{
+    int ret;
+    uint32_t magic;
+    VMDK3Header header;
+    BDRVVmdkState *s = bs->opaque;
+    VmdkExtent *extent;
 
-    /* write the descriptor */
-    if (lseek(snp_fd, 0x200, SEEK_SET) == -1) {
-        ret = -errno;
+    s->desc_offset = 0x200;
+    ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
+    if (ret < 0) {
         goto fail;
     }
-    if (write(snp_fd, s_desc, strlen(s_desc)) == -1) {
-        ret = -errno;
+    extent = vmdk_add_extent(bs,
+                             bs->file, false,
+                             le32_to_cpu(header.disk_sectors),
+                             le32_to_cpu(header.l1dir_offset) << 9,
+                             0, 1 << 6, 1 << 9,
+                             le32_to_cpu(header.granularity));
+    ret = vmdk_init_tables(bs, extent);
+    if (ret) {
+        /* vmdk_init_tables cleans up on fail, so only free allocation of
+         * vmdk_add_extent here. */
         goto fail;
     }
+    return 0;
+ fail:
+    vmdk_free_extents(bs);
+    return ret;
+}
 
-    gd_offset = header.gd_offset * SECTOR_SIZE;     // offset of GD table
-    rgd_offset = header.rgd_offset * SECTOR_SIZE;   // offset of RGD table
-    capacity = header.capacity * SECTOR_SIZE;       // Extent size
-    /*
-     * Each GDE span 32M disk, means:
-     * 512 GTE per GT, each GTE points to grain
-     */
-    gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
-    if (!gt_size) {
-        ret = -EINVAL;
-        goto fail;
-    }
-    gde_entries = (uint32_t)(capacity / gt_size);  // number of gde/rgde
-    gd_size = gde_entries * sizeof(uint32_t);
+static int vmdk_open_vmdk4(BlockDriverState *bs, int flags)
+{
+    int ret;
+    uint32_t magic;
+    uint32_t l1_size, l1_entry_sectors;
+    VMDK4Header header;
+    BDRVVmdkState *s = bs->opaque;
+    VmdkExtent *extent;
 
-    /* write RGD */
-    rgd_buf = qemu_malloc(gd_size);
-    if (lseek(p_fd, rgd_offset, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail_rgd;
+    s->desc_offset = 0x200;
+    ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
+    if (ret < 0) {
+        goto fail;
     }
-    if (read(p_fd, rgd_buf, gd_size) != gd_size) {
-        ret = -errno;
-        goto fail_rgd;
+    l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
+                        * le64_to_cpu(header.granularity);
+    l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
+                / l1_entry_sectors;
+    extent = vmdk_add_extent(bs, bs->file, false,
+                          le64_to_cpu(header.capacity),
+                          le64_to_cpu(header.gd_offset) << 9,
+                          le64_to_cpu(header.rgd_offset) << 9,
+                          l1_size,
+                          le32_to_cpu(header.num_gtes_per_gte),
+                          le64_to_cpu(header.granularity));
+    if (extent->l1_entry_sectors <= 0) {
+        ret = -EINVAL;
+        goto fail;
     }
-    if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail_rgd;
+    /* try to open parent images, if exist */
+    ret = vmdk_parent_open(bs);
+    if (ret) {
+        goto fail;
     }
-    if (write(snp_fd, rgd_buf, gd_size) == -1) {
-        ret = -errno;
-        goto fail_rgd;
+    s->parent_cid = vmdk_read_cid(bs, 1);
+    ret = vmdk_init_tables(bs, extent);
+    if (ret) {
+        goto fail;
     }
+    return 0;
+ fail:
+    vmdk_free_extents(bs);
+    return ret;
+}
 
-    /* write GD */
-    gd_buf = qemu_malloc(gd_size);
-    if (lseek(p_fd, gd_offset, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail_gd;
+/* find an option value out of descriptor file */
+static int vmdk_parse_description(const char *desc, const char *opt_name,
+        char *buf, int buf_size)
+{
+    char *opt_pos, *opt_end;
+    const char *end = desc + strlen(desc);
+
+    opt_pos = strstr(desc, opt_name);
+    if (!opt_pos) {
+        return -1;
     }
-    if (read(p_fd, gd_buf, gd_size) != gd_size) {
-        ret = -errno;
-        goto fail_gd;
+    /* Skip "=\"" following opt_name */
+    opt_pos += strlen(opt_name) + 2;
+    if (opt_pos >= end) {
+        return -1;
     }
-    if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail_gd;
+    opt_end = opt_pos;
+    while (opt_end < end && *opt_end != '"') {
+        opt_end++;
     }
-    if (write(snp_fd, gd_buf, gd_size) == -1) {
-        ret = -errno;
-        goto fail_gd;
+    if (opt_end == end || buf_size < opt_end - opt_pos + 1) {
+        return -1;
     }
-    ret = 0;
-
-fail_gd:
-    qemu_free(gd_buf);
-fail_rgd:
-    qemu_free(rgd_buf);
-fail:
-    close(p_fd);
-    close(snp_fd);
-    return ret;
+    pstrcpy(buf, opt_end - opt_pos + 1, opt_pos);
+    return 0;
 }
 
-static int vmdk_parent_open(BlockDriverState *bs)
+static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
+        const char *desc_file_path)
 {
-    char *p_name;
-    char desc[DESC_SIZE];
+    int ret;
+    char access[11];
+    char type[11];
+    char fname[512];
+    const char *p = desc;
+    int64_t sectors = 0;
+    int64_t flat_offset;
+
+    while (*p) {
+        /* parse extent line:
+         * RW [size in sectors] FLAT "file-name.vmdk" OFFSET
+         * or
+         * RW [size in sectors] SPARSE "file-name.vmdk"
+         */
+        flat_offset = -1;
+        ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64,
+                access, &sectors, type, fname, &flat_offset);
+        if (ret < 4 || strcmp(access, "RW")) {
+            goto next_line;
+        } else if (!strcmp(type, "FLAT")) {
+            if (ret != 5 || flat_offset < 0) {
+                return -EINVAL;
+            }
+        } else if (ret != 4) {
+            return -EINVAL;
+        }
 
-    /* the descriptor offset = 0x200 */
-    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
-        return -1;
+        /* trim the quotation marks around */
+        if (fname[0] == '"') {
+            memmove(fname, fname + 1, strlen(fname));
+            if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') {
+                return -EINVAL;
+            }
+            fname[strlen(fname) - 1] = '\0';
+        }
+        if (sectors <= 0 ||
+            (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) ||
+            (strcmp(access, "RW"))) {
+            goto next_line;
+        }
 
-    if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) {
-        char *end_name;
+        /* save to extents array */
+        if (!strcmp(type, "FLAT")) {
+            /* FLAT extent */
+            char extent_path[PATH_MAX];
+            BlockDriverState *extent_file;
+            VmdkExtent *extent;
+
+            path_combine(extent_path, sizeof(extent_path),
+                    desc_file_path, fname);
+            ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
+            if (ret) {
+                return ret;
+            }
+            extent = vmdk_add_extent(bs, extent_file, true, sectors,
+                            0, 0, 0, 0, sectors);
+            extent->flat_start_offset = flat_offset;
+        } else {
+            /* SPARSE extent, not supported for now */
+            fprintf(stderr,
+                "VMDK: Not supported extent type \"%s\""".\n", type);
+            return -ENOTSUP;
+        }
+next_line:
+        /* move to next line */
+        while (*p && *p != '\n') {
+            p++;
+        }
+        p++;
+    }
+    return 0;
+}
 
-        p_name += sizeof("parentFileNameHint") + 1;
-        if ((end_name = strchr(p_name,'\"')) == NULL)
-            return -1;
-        if ((end_name - p_name) > sizeof (bs->backing_file) - 1)
-            return -1;
+static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
+{
+    int ret;
+    char buf[2048];
+    char ct[128];
+    BDRVVmdkState *s = bs->opaque;
 
-        pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
+    ret = bdrv_pread(bs->file, 0, buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+    buf[2047] = '\0';
+    if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
+        return -EINVAL;
+    }
+    if (strcmp(ct, "monolithicFlat")) {
+        fprintf(stderr,
+                "VMDK: Not supported image type \"%s\""".\n", ct);
+        return -ENOTSUP;
+    }
+    s->desc_offset = 0;
+    ret = vmdk_parse_extents(buf, bs, bs->file->filename);
+    if (ret) {
+        return ret;
     }
 
+    /* try to open parent images, if exist */
+    if (vmdk_parent_open(bs)) {
+        qemu_free(s->extents);
+        return -EINVAL;
+    }
+    s->parent_cid = vmdk_read_cid(bs, 1);
     return 0;
 }
 
 static int vmdk_open(BlockDriverState *bs, int flags)
 {
-    BDRVVmdkState *s = bs->opaque;
     uint32_t magic;
-    int l1_size, i;
 
-    if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic))
-        goto fail;
+    if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
+        return -EIO;
+    }
 
     magic = be32_to_cpu(magic);
     if (magic == VMDK3_MAGIC) {
-        VMDK3Header header;
-
-        if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header))
-            goto fail;
-        s->cluster_sectors = le32_to_cpu(header.granularity);
-        s->l2_size = 1 << 9;
-        s->l1_size = 1 << 6;
-        bs->total_sectors = le32_to_cpu(header.disk_sectors);
-        s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9;
-        s->l1_backup_table_offset = 0;
-        s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
+        return vmdk_open_vmdk3(bs, flags);
     } else if (magic == VMDK4_MAGIC) {
-        VMDK4Header header;
-
-        if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header))
-            goto fail;
-        bs->total_sectors = le64_to_cpu(header.capacity);
-        s->cluster_sectors = le64_to_cpu(header.granularity);
-        s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
-        s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
-        if (s->l1_entry_sectors <= 0)
-            goto fail;
-        s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
-            / s->l1_entry_sectors;
-        s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
-        s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
-
-        // try to open parent images, if exist
-        if (vmdk_parent_open(bs) != 0)
-            goto fail;
-        // write the CID once after the image creation
-        s->parent_cid = vmdk_read_cid(bs,1);
+        return vmdk_open_vmdk4(bs, flags);
     } else {
-        goto fail;
-    }
-
-    /* read the L1 table */
-    l1_size = s->l1_size * sizeof(uint32_t);
-    s->l1_table = qemu_malloc(l1_size);
-    if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
-        goto fail;
-    for(i = 0; i < s->l1_size; i++) {
-        le32_to_cpus(&s->l1_table[i]);
-    }
-
-    if (s->l1_backup_table_offset) {
-        s->l1_backup_table = qemu_malloc(l1_size);
-        if (bdrv_pread(bs->file, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
-            goto fail;
-        for(i = 0; i < s->l1_size; i++) {
-            le32_to_cpus(&s->l1_backup_table[i]);
-        }
+        return vmdk_open_desc_file(bs, flags);
     }
-
-    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
-    return 0;
- fail:
-    qemu_free(s->l1_backup_table);
-    qemu_free(s->l1_table);
-    qemu_free(s->l2_cache);
-    return -1;
 }
 
-static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
-                                   uint64_t offset, int allocate);
-
-static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
-                             uint64_t offset, int allocate)
+static int get_whole_cluster(BlockDriverState *bs,
+                VmdkExtent *extent,
+                uint64_t cluster_offset,
+                uint64_t offset,
+                bool allocate)
 {
-    BDRVVmdkState *s = bs->opaque;
-    uint8_t  whole_grain[s->cluster_sectors*512];        // 128 sectors * 512 bytes each = grain size 64KB
+    /* 128 sectors * 512 bytes each = grain size 64KB */
+    uint8_t  whole_grain[extent->cluster_sectors * 512];
 
-    // we will be here if it's first write on non-exist grain(cluster).
-    // try to read from parent image, if exist
+    /* we will be here if it's first write on non-exist grain(cluster).
+     * try to read from parent image, if exist */
     if (bs->backing_hd) {
         int ret;
 
-        if (!vmdk_is_cid_valid(bs))
+        if (!vmdk_is_cid_valid(bs)) {
             return -1;
+        }
 
+        /* floor offset to cluster */
+        offset -= offset % (extent->cluster_sectors * 512);
         ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
-            s->cluster_sectors);
+                extent->cluster_sectors);
         if (ret < 0) {
             return -1;
         }
 
-        //Write grain only into the active image
-        ret = bdrv_write(bs->file, cluster_offset, whole_grain,
-            s->cluster_sectors);
+        /* Write grain only into the active image */
+        ret = bdrv_write(extent->file, cluster_offset, whole_grain,
+                extent->cluster_sectors);
         if (ret < 0) {
             return -1;
         }
@@ -465,85 +625,112 @@ static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
     return 0;
 }
 
-static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
+static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
 {
-    BDRVVmdkState *s = bs->opaque;
-
     /* update L2 table */
-    if (bdrv_pwrite_sync(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
-                    &(m_data->offset), sizeof(m_data->offset)) < 0)
+    if (bdrv_pwrite_sync(
+                extent->file,
+                ((int64_t)m_data->l2_offset * 512)
+                    + (m_data->l2_index * sizeof(m_data->offset)),
+                &(m_data->offset),
+                sizeof(m_data->offset)
+            ) < 0) {
         return -1;
+    }
     /* update backup L2 table */
-    if (s->l1_backup_table_offset != 0) {
-        m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
-        if (bdrv_pwrite_sync(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
-                        &(m_data->offset), sizeof(m_data->offset)) < 0)
+    if (extent->l1_backup_table_offset != 0) {
+        m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
+        if (bdrv_pwrite_sync(
+                    extent->file,
+                    ((int64_t)m_data->l2_offset * 512)
+                        + (m_data->l2_index * sizeof(m_data->offset)),
+                    &(m_data->offset), sizeof(m_data->offset)
+                ) < 0) {
             return -1;
+        }
     }
 
     return 0;
 }
 
-static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
-                                   uint64_t offset, int allocate)
+static int get_cluster_offset(BlockDriverState *bs,
+                                    VmdkExtent *extent,
+                                    VmdkMetaData *m_data,
+                                    uint64_t offset,
+                                    int allocate,
+                                    uint64_t *cluster_offset)
 {
-    BDRVVmdkState *s = bs->opaque;
     unsigned int l1_index, l2_offset, l2_index;
     int min_index, i, j;
     uint32_t min_count, *l2_table, tmp = 0;
-    uint64_t cluster_offset;
 
-    if (m_data)
+    if (m_data) {
         m_data->valid = 0;
-
-    l1_index = (offset >> 9) / s->l1_entry_sectors;
-    if (l1_index >= s->l1_size)
-        return 0;
-    l2_offset = s->l1_table[l1_index];
-    if (!l2_offset)
+    }
+    if (extent->flat) {
+        *cluster_offset = extent->flat_start_offset;
         return 0;
-    for(i = 0; i < L2_CACHE_SIZE; i++) {
-        if (l2_offset == s->l2_cache_offsets[i]) {
+    }
+
+    l1_index = (offset >> 9) / extent->l1_entry_sectors;
+    if (l1_index >= extent->l1_size) {
+        return -1;
+    }
+    l2_offset = extent->l1_table[l1_index];
+    if (!l2_offset) {
+        return -1;
+    }
+    for (i = 0; i < L2_CACHE_SIZE; i++) {
+        if (l2_offset == extent->l2_cache_offsets[i]) {
             /* increment the hit count */
-            if (++s->l2_cache_counts[i] == 0xffffffff) {
-                for(j = 0; j < L2_CACHE_SIZE; j++) {
-                    s->l2_cache_counts[j] >>= 1;
+            if (++extent->l2_cache_counts[i] == 0xffffffff) {
+                for (j = 0; j < L2_CACHE_SIZE; j++) {
+                    extent->l2_cache_counts[j] >>= 1;
                 }
             }
-            l2_table = s->l2_cache + (i * s->l2_size);
+            l2_table = extent->l2_cache + (i * extent->l2_size);
             goto found;
         }
     }
     /* not found: load a new entry in the least used one */
     min_index = 0;
     min_count = 0xffffffff;
-    for(i = 0; i < L2_CACHE_SIZE; i++) {
-        if (s->l2_cache_counts[i] < min_count) {
-            min_count = s->l2_cache_counts[i];
+    for (i = 0; i < L2_CACHE_SIZE; i++) {
+        if (extent->l2_cache_counts[i] < min_count) {
+            min_count = extent->l2_cache_counts[i];
             min_index = i;
         }
     }
-    l2_table = s->l2_cache + (min_index * s->l2_size);
-    if (bdrv_pread(bs->file, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
-                                                                        s->l2_size * sizeof(uint32_t))
-        return 0;
+    l2_table = extent->l2_cache + (min_index * extent->l2_size);
+    if (bdrv_pread(
+                extent->file,
+                (int64_t)l2_offset * 512,
+                l2_table,
+                extent->l2_size * sizeof(uint32_t)
+            ) != extent->l2_size * sizeof(uint32_t)) {
+        return -1;
+    }
 
-    s->l2_cache_offsets[min_index] = l2_offset;
-    s->l2_cache_counts[min_index] = 1;
+    extent->l2_cache_offsets[min_index] = l2_offset;
+    extent->l2_cache_counts[min_index] = 1;
  found:
-    l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
-    cluster_offset = le32_to_cpu(l2_table[l2_index]);
+    l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
+    *cluster_offset = le32_to_cpu(l2_table[l2_index]);
 
-    if (!cluster_offset) {
-        if (!allocate)
-            return 0;
+    if (!*cluster_offset) {
+        if (!allocate) {
+            return -1;
+        }
 
-        // Avoid the L2 tables update for the images that have snapshots.
-        cluster_offset = bdrv_getlength(bs->file);
-        bdrv_truncate(bs->file, cluster_offset + (s->cluster_sectors << 9));
+        /* Avoid the L2 tables update for the images that have snapshots. */
+        *cluster_offset = bdrv_getlength(extent->file);
+        bdrv_truncate(
+            extent->file,
+            *cluster_offset + (extent->cluster_sectors << 9)
+        );
 
-        cluster_offset >>= 9;
-        tmp = cpu_to_le32(cluster_offset);
+        *cluster_offset >>= 9;
+        tmp = cpu_to_le32(*cluster_offset);
         l2_table[l2_index] = tmp;
 
         /* First of all we write grain itself, to avoid race condition
@@ -551,8 +738,10 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
          * This problem may occur because of insufficient space on host disk
          * or inappropriate VM shutdown.
          */
-        if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
-            return 0;
+        if (get_whole_cluster(
+                bs, extent, *cluster_offset, offset, allocate) == -1) {
+            return -1;
+        }
 
         if (m_data) {
             m_data->offset = tmp;
@@ -562,53 +751,95 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
             m_data->valid = 1;
         }
     }
-    cluster_offset <<= 9;
-    return cluster_offset;
+    *cluster_offset <<= 9;
+    return 0;
+}
+
+static VmdkExtent *find_extent(BDRVVmdkState *s,
+                                int64_t sector_num, VmdkExtent *start_hint)
+{
+    VmdkExtent *extent = start_hint;
+
+    if (!extent) {
+        extent = &s->extents[0];
+    }
+    while (extent < &s->extents[s->num_extents]) {
+        if (sector_num < extent->end_sector) {
+            return extent;
+        }
+        extent++;
+    }
+    return NULL;
 }
 
 static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum)
 {
     BDRVVmdkState *s = bs->opaque;
-    int index_in_cluster, n;
-    uint64_t cluster_offset;
+    int64_t index_in_cluster, n, ret;
+    uint64_t offset;
+    VmdkExtent *extent;
 
-    cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
-    index_in_cluster = sector_num % s->cluster_sectors;
-    n = s->cluster_sectors - index_in_cluster;
-    if (n > nb_sectors)
+    extent = find_extent(s, sector_num, NULL);
+    if (!extent) {
+        return 0;
+    }
+    ret = get_cluster_offset(bs, extent, NULL,
+                            sector_num * 512, 0, &offset);
+    /* get_cluster_offset returning 0 means success */
+    ret = !ret;
+
+    index_in_cluster = sector_num % extent->cluster_sectors;
+    n = extent->cluster_sectors - index_in_cluster;
+    if (n > nb_sectors) {
         n = nb_sectors;
+    }
     *pnum = n;
-    return (cluster_offset != 0);
+    return ret;
 }
 
 static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVVmdkState *s = bs->opaque;
-    int index_in_cluster, n, ret;
+    int ret;
+    uint64_t n, index_in_cluster;
+    VmdkExtent *extent = NULL;
     uint64_t cluster_offset;
 
     while (nb_sectors > 0) {
-        cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
-        index_in_cluster = sector_num % s->cluster_sectors;
-        n = s->cluster_sectors - index_in_cluster;
-        if (n > nb_sectors)
+        extent = find_extent(s, sector_num, extent);
+        if (!extent) {
+            return -EIO;
+        }
+        ret = get_cluster_offset(
+                            bs, extent, NULL,
+                            sector_num << 9, 0, &cluster_offset);
+        index_in_cluster = sector_num % extent->cluster_sectors;
+        n = extent->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors) {
             n = nb_sectors;
-        if (!cluster_offset) {
-            // try to read from parent image, if exist
+        }
+        if (ret) {
+            /* if not allocated, try to read from parent image, if exist */
             if (bs->backing_hd) {
-                if (!vmdk_is_cid_valid(bs))
-                    return -1;
+                if (!vmdk_is_cid_valid(bs)) {
+                    return -EINVAL;
+                }
                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
-                if (ret < 0)
-                    return -1;
+                if (ret < 0) {
+                    return ret;
+                }
             } else {
                 memset(buf, 0, 512 * n);
             }
         } else {
-            if(bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
-                return -1;
+            ret = bdrv_pread(extent->file,
+                            cluster_offset + index_in_cluster * 512,
+                            buf, n * 512);
+            if (ret < 0) {
+                return ret;
+            }
         }
         nb_sectors -= n;
         sector_num += n;
@@ -621,110 +852,101 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
     BDRVVmdkState *s = bs->opaque;
-    VmdkMetaData m_data;
-    int index_in_cluster, n;
+    VmdkExtent *extent = NULL;
+    int n, ret;
+    int64_t index_in_cluster;
     uint64_t cluster_offset;
-    static int cid_update = 0;
+    VmdkMetaData m_data;
 
     if (sector_num > bs->total_sectors) {
         fprintf(stderr,
                 "(VMDK) Wrong offset: sector_num=0x%" PRIx64
                 " total_sectors=0x%" PRIx64 "\n",
                 sector_num, bs->total_sectors);
-        return -1;
+        return -EIO;
     }
 
     while (nb_sectors > 0) {
-        index_in_cluster = sector_num & (s->cluster_sectors - 1);
-        n = s->cluster_sectors - index_in_cluster;
-        if (n > nb_sectors)
+        extent = find_extent(s, sector_num, extent);
+        if (!extent) {
+            return -EIO;
+        }
+        ret = get_cluster_offset(
+                                bs,
+                                extent,
+                                &m_data,
+                                sector_num << 9, 1,
+                                &cluster_offset);
+        if (ret) {
+            return -EINVAL;
+        }
+        index_in_cluster = sector_num % extent->cluster_sectors;
+        n = extent->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors) {
             n = nb_sectors;
-        cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1);
-        if (!cluster_offset)
-            return -1;
+        }
 
-        if (bdrv_pwrite(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
-            return -1;
+        ret = bdrv_pwrite(extent->file,
+                        cluster_offset + index_in_cluster * 512,
+                        buf,
+                        n * 512);
+        if (ret < 0) {
+            return ret;
+        }
         if (m_data.valid) {
             /* update L2 tables */
-            if (vmdk_L2update(bs, &m_data) == -1)
-                return -1;
+            if (vmdk_L2update(extent, &m_data) == -1) {
+                return -EIO;
+            }
         }
         nb_sectors -= n;
         sector_num += n;
         buf += n * 512;
 
-        // update CID on the first write every time the virtual disk is opened
-        if (!cid_update) {
+        /* update CID on the first write every time the virtual disk is
+         * opened */
+        if (!s->cid_updated) {
             vmdk_write_cid(bs, time(NULL));
-            cid_update++;
+            s->cid_updated = true;
         }
     }
     return 0;
 }
 
-static int vmdk_create(const char *filename, QEMUOptionParameter *options)
+
+static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
 {
-    int fd, i;
+    int ret, i;
+    int fd = 0;
     VMDK4Header header;
     uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
-    static const char desc_template[] =
-        "# Disk DescriptorFile\n"
-        "version=1\n"
-        "CID=%x\n"
-        "parentCID=ffffffff\n"
-        "createType=\"monolithicSparse\"\n"
-        "\n"
-        "# Extent description\n"
-        "RW %" PRId64 " SPARSE \"%s\"\n"
-        "\n"
-        "# The Disk Data Base \n"
-        "#DDB\n"
-        "\n"
-        "ddb.virtualHWVersion = \"%d\"\n"
-        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
-        "ddb.geometry.heads = \"16\"\n"
-        "ddb.geometry.sectors = \"63\"\n"
-        "ddb.adapterType = \"ide\"\n";
-    char desc[1024];
-    const char *real_filename, *temp_str;
-    int64_t total_size = 0;
-    const char *backing_file = NULL;
-    int flags = 0;
-    int ret;
 
-    // Read out options
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n / 512;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
-            backing_file = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
-            flags |= options->value.n ? BLOCK_FLAG_COMPAT6: 0;
-        }
-        options++;
+    fd = open(
+        filename,
+        O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+        0644);
+    if (fd < 0) {
+        return -errno;
     }
-
-    /* XXX: add support for backing file */
-    if (backing_file) {
-        return vmdk_snapshot_create(filename, backing_file);
+    if (flat) {
+        ret = ftruncate(fd, filesize);
+        if (ret < 0) {
+            ret = -errno;
+        }
+        goto exit;
     }
-
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
-              0644);
-    if (fd < 0)
-        return -errno;
     magic = cpu_to_be32(VMDK4_MAGIC);
     memset(&header, 0, sizeof(header));
     header.version = 1;
     header.flags = 3; /* ?? */
-    header.capacity = total_size;
+    header.capacity = filesize / 512;
     header.granularity = 128;
     header.num_gtes_per_gte = 512;
 
-    grains = (total_size + header.granularity - 1) / header.granularity;
+    grains = (filesize / 512 + header.granularity - 1) / header.granularity;
     gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
-    gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
+    gt_count =
+        (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
     gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
 
     header.desc_offset = 1;
@@ -735,7 +957,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
        ((header.gd_offset + gd_size + (gt_size * gt_count) +
          header.granularity - 1) / header.granularity) *
         header.granularity;
-
     /* swap endianness for all header fields */
     header.version = cpu_to_le32(header.version);
     header.flags = cpu_to_le32(header.flags);
@@ -793,27 +1014,255 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
         }
     }
 
-    /* compose the descriptor */
-    real_filename = filename;
-    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
-        real_filename = temp_str + 1;
-    if ((temp_str = strrchr(real_filename, '/')) != NULL)
-        real_filename = temp_str + 1;
-    if ((temp_str = strrchr(real_filename, ':')) != NULL)
-        real_filename = temp_str + 1;
-    snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL),
-             total_size, real_filename,
-             (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
-             total_size / (int64_t)(63 * 16));
+    ret = 0;
+ exit:
+    close(fd);
+    return ret;
+}
+
+static int filename_decompose(const char *filename, char *path, char *prefix,
+        char *postfix, size_t buf_len)
+{
+    const char *p, *q;
+
+    if (filename == NULL || !strlen(filename)) {
+        fprintf(stderr, "Vmdk: no filename provided.\n");
+        return -1;
+    }
+    p = strrchr(filename, '/');
+    if (p == NULL) {
+        p = strrchr(filename, '\\');
+    }
+    if (p == NULL) {
+        p = strrchr(filename, ':');
+    }
+    if (p != NULL) {
+        p++;
+        if (p - filename >= buf_len) {
+            return -1;
+        }
+        pstrcpy(path, p - filename + 1, filename);
+    } else {
+        p = filename;
+        path[0] = '\0';
+    }
+    q = strrchr(p, '.');
+    if (q == NULL) {
+        pstrcpy(prefix, buf_len, p);
+        postfix[0] = '\0';
+    } else {
+        if (q - p >= buf_len) {
+            return -1;
+        }
+        pstrcpy(prefix, q - p + 1, p);
+        pstrcpy(postfix, buf_len, q);
+    }
+    return 0;
+}
+
+static int relative_path(char *dest, int dest_size,
+        const char *base, const char *target)
+{
+    int i = 0;
+    int n = 0;
+    const char *p, *q;
+#ifdef _WIN32
+    const char *sep = "\\";
+#else
+    const char *sep = "/";
+#endif
+
+    if (!(dest && base && target)) {
+        return -1;
+    }
+    if (path_is_absolute(target)) {
+        dest[dest_size - 1] = '\0';
+        strncpy(dest, target, dest_size - 1);
+        return 0;
+    }
+    while (base[i] == target[i]) {
+        i++;
+    }
+    p = &base[i];
+    q = &target[i];
+    while (*p) {
+        if (*p == *sep) {
+            n++;
+        }
+        p++;
+    }
+    dest[0] = '\0';
+    for (; n; n--) {
+        pstrcat(dest, dest_size, "..");
+        pstrcat(dest, dest_size, sep);
+    }
+    pstrcat(dest, dest_size, q);
+    return 0;
+}
+
+static int vmdk_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd, idx = 0;
+    char desc[BUF_SIZE];
+    int64_t total_size = 0, filesize;
+    const char *backing_file = NULL;
+    const char *fmt = NULL;
+    int flags = 0;
+    int ret = 0;
+    bool flat, split;
+    char ext_desc_lines[BUF_SIZE] = "";
+    char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
+    const int64_t split_size = 0x80000000;  /* VMDK has constant split size */
+    const char *desc_extent_line;
+    char parent_desc_line[BUF_SIZE] = "";
+    uint32_t parent_cid = 0xffffffff;
+    const char desc_template[] =
+        "# Disk DescriptorFile\n"
+        "version=1\n"
+        "CID=%x\n"
+        "parentCID=%x\n"
+        "createType=\"%s\"\n"
+        "%s"
+        "\n"
+        "# Extent description\n"
+        "%s"
+        "\n"
+        "# The Disk Data Base\n"
+        "#DDB\n"
+        "\n"
+        "ddb.virtualHWVersion = \"%d\"\n"
+        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
+        "ddb.geometry.heads = \"16\"\n"
+        "ddb.geometry.sectors = \"63\"\n"
+        "ddb.adapterType = \"ide\"\n";
+
+    if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
+        return -EINVAL;
+    }
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
+            flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
+        } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
+            fmt = options->value.s;
+        }
+        options++;
+    }
+    if (!fmt) {
+        /* Default format to monolithicSparse */
+        fmt = "monolithicSparse";
+    } else if (strcmp(fmt, "monolithicFlat") &&
+               strcmp(fmt, "monolithicSparse") &&
+               strcmp(fmt, "twoGbMaxExtentSparse") &&
+               strcmp(fmt, "twoGbMaxExtentFlat")) {
+        fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
+        return -EINVAL;
+    }
+    split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
+              strcmp(fmt, "twoGbMaxExtentSparse"));
+    flat = !(strcmp(fmt, "monolithicFlat") &&
+             strcmp(fmt, "twoGbMaxExtentFlat"));
+    if (flat) {
+        desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
+    } else {
+        desc_extent_line = "RW %lld SPARSE \"%s\"\n";
+    }
+    if (flat && backing_file) {
+        /* not supporting backing file for flat image */
+        return -ENOTSUP;
+    }
+    if (backing_file) {
+        char parent_filename[PATH_MAX];
+        BlockDriverState *bs = bdrv_new("");
+        ret = bdrv_open(bs, backing_file, 0, NULL);
+        if (ret != 0) {
+            bdrv_delete(bs);
+            return ret;
+        }
+        if (strcmp(bs->drv->format_name, "vmdk")) {
+            bdrv_delete(bs);
+            return -EINVAL;
+        }
+        filesize = bdrv_getlength(bs);
+        parent_cid = vmdk_read_cid(bs, 0);
+        bdrv_delete(bs);
+        relative_path(parent_filename, sizeof(parent_filename),
+                      filename, backing_file);
+        snprintf(parent_desc_line, sizeof(parent_desc_line),
+                "parentFileNameHint=\"%s\"", parent_filename);
+    }
+
+    /* Create extents */
+    filesize = total_size;
+    while (filesize > 0) {
+        char desc_line[BUF_SIZE];
+        char ext_filename[PATH_MAX];
+        char desc_filename[PATH_MAX];
+        int64_t size = filesize;
 
-    /* write the descriptor */
-    lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
+        if (split && size > split_size) {
+            size = split_size;
+        }
+        if (split) {
+            snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s",
+                    prefix, flat ? 'f' : 's', ++idx, postfix);
+        } else if (flat) {
+            snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s",
+                    prefix, postfix);
+        } else {
+            snprintf(desc_filename, sizeof(desc_filename), "%s%s",
+                    prefix, postfix);
+        }
+        snprintf(ext_filename, sizeof(ext_filename), "%s%s",
+                path, desc_filename);
+
+        if (vmdk_create_extent(ext_filename, size, flat)) {
+            return -EINVAL;
+        }
+        filesize -= size;
+
+        /* Format description line */
+        snprintf(desc_line, sizeof(desc_line),
+                    desc_extent_line, size / 512, desc_filename);
+        pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line);
+    }
+    /* generate descriptor file */
+    snprintf(desc, sizeof(desc), desc_template,
+            (unsigned int)time(NULL),
+            parent_cid,
+            fmt,
+            parent_desc_line,
+            ext_desc_lines,
+            (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
+            total_size / (int64_t)(63 * 16 * 512));
+    if (split || flat) {
+        fd = open(
+                filename,
+                O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+                0644);
+    } else {
+        fd = open(
+                filename,
+                O_WRONLY | O_BINARY | O_LARGEFILE,
+                0644);
+    }
+    if (fd < 0) {
+        return -errno;
+    }
+    /* the descriptor offset = 0x200 */
+    if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
+        ret = -errno;
+        goto exit;
+    }
     ret = qemu_write_full(fd, desc, strlen(desc));
     if (ret != strlen(desc)) {
         ret = -errno;
         goto exit;
     }
-
     ret = 0;
 exit:
     close(fd);
@@ -822,17 +1271,47 @@ exit:
 
 static void vmdk_close(BlockDriverState *bs)
 {
-    BDRVVmdkState *s = bs->opaque;
-
-    qemu_free(s->l1_table);
-    qemu_free(s->l2_cache);
+    vmdk_free_extents(bs);
 }
 
 static int vmdk_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
+    int i, ret, err;
+    BDRVVmdkState *s = bs->opaque;
+
+    ret = bdrv_flush(bs->file);
+    for (i = 0; i < s->num_extents; i++) {
+        err = bdrv_flush(s->extents[i].file);
+        if (err < 0) {
+            ret = err;
+        }
+    }
+    return ret;
 }
 
+static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
+{
+    int i;
+    int64_t ret = 0;
+    int64_t r;
+    BDRVVmdkState *s = bs->opaque;
+
+    ret = bdrv_get_allocated_file_size(bs->file);
+    if (ret < 0) {
+        return ret;
+    }
+    for (i = 0; i < s->num_extents; i++) {
+        if (s->extents[i].file == bs->file) {
+            continue;
+        }
+        r = bdrv_get_allocated_file_size(s->extents[i].file);
+        if (r < 0) {
+            return r;
+        }
+        ret += r;
+    }
+    return ret;
+}
 
 static QEMUOptionParameter vmdk_create_options[] = {
     {
@@ -850,20 +1329,28 @@ static QEMUOptionParameter vmdk_create_options[] = {
         .type = OPT_FLAG,
         .help = "VMDK version 6 image"
     },
+    {
+        .name = BLOCK_OPT_SUBFMT,
+        .type = OPT_STRING,
+        .help =
+            "VMDK flat extent format, can be one of "
+            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat} "
+    },
     { NULL }
 };
 
 static BlockDriver bdrv_vmdk = {
-    .format_name       = "vmdk",
-    .instance_size     = sizeof(BDRVVmdkState),
-    .bdrv_probe                = vmdk_probe,
+    .format_name    = "vmdk",
+    .instance_size  = sizeof(BDRVVmdkState),
+    .bdrv_probe     = vmdk_probe,
     .bdrv_open      = vmdk_open,
-    .bdrv_read         = vmdk_read,
-    .bdrv_write                = vmdk_write,
-    .bdrv_close                = vmdk_close,
-    .bdrv_create       = vmdk_create,
-    .bdrv_flush                = vmdk_flush,
-    .bdrv_is_allocated = vmdk_is_allocated,
+    .bdrv_read      = vmdk_read,
+    .bdrv_write     = vmdk_write,
+    .bdrv_close     = vmdk_close,
+    .bdrv_create    = vmdk_create,
+    .bdrv_flush     = vmdk_flush,
+    .bdrv_is_allocated  = vmdk_is_allocated,
+    .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
 
     .create_options = vmdk_create_options,
 };
index 1e265d274daaa40c56ed2b4c104d80c16143f2f6..efb68038c4c6cc79b85c055cdd92cd4d8fd7f962 100644 (file)
@@ -39,6 +39,7 @@
 #define BLOCK_OPT_CLUSTER_SIZE  "cluster_size"
 #define BLOCK_OPT_TABLE_SIZE    "table_size"
 #define BLOCK_OPT_PREALLOC      "preallocation"
+#define BLOCK_OPT_SUBFMT        "subformat"
 
 typedef struct AIOPool {
     void (*cancel)(BlockDriverAIOCB *acb);
@@ -85,6 +86,7 @@ struct BlockDriver {
     const char *protocol_name;
     int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
     int64_t (*bdrv_getlength)(BlockDriverState *bs);
+    int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs);
     int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
                                  const uint8_t *buf, int nb_sectors);
 
index aa50800a56dd0e864473301574aba5b565539c4b..9ddd6373c83a98a10d287708a3f5826f3fdad791 100644 (file)
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -244,7 +244,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
 
     DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
     lun = busid & 7;
-    s->current_req = scsi_req_new(s->current_dev, 0, lun);
+    s->current_req = scsi_req_new(s->current_dev, 0, lun, NULL);
     datalen = scsi_req_enqueue(s->current_req, buf);
     s->ti_size = datalen;
     if (datalen != 0) {
index 940b43abfd26ae0c3da8f6ec6d3f18c02fb461d4..69eec1d2fe0a1879b92e4eca76a05249227a045e 100644 (file)
@@ -661,7 +661,7 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
 static void lsi_request_cancelled(SCSIRequest *req)
 {
     LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
-    lsi_request *p;
+    lsi_request *p = req->hba_private;
 
     if (s->current && req == s->current->req) {
         scsi_req_unref(req);
@@ -670,7 +670,6 @@ static void lsi_request_cancelled(SCSIRequest *req)
         return;
     }
 
-    p = lsi_find_by_tag(s, req->tag);
     if (p) {
         QTAILQ_REMOVE(&s->queue, p, next);
         scsi_req_unref(req);
@@ -680,18 +679,12 @@ static void lsi_request_cancelled(SCSIRequest *req)
 
 /* Record that data is available for a queued command.  Returns zero if
    the device was reselected, nonzero if the IO is deferred.  */
-static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t len)
+static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
 {
-    lsi_request *p;
-
-    p = lsi_find_by_tag(s, tag);
-    if (!p) {
-        BADF("IO with unknown tag %d\n", tag);
-        return 1;
-    }
+    lsi_request *p = req->hba_private;
 
     if (p->pending) {
-        BADF("Multiple IO pending for tag %d\n", tag);
+        BADF("Multiple IO pending for request %p\n", p);
     }
     p->pending = len;
     /* Reselect if waiting for it, or if reselection triggers an IRQ
@@ -743,9 +736,9 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
     LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
     int out;
 
-    if (s->waiting == 1 || !s->current || req->tag != s->current->tag ||
+    if (s->waiting == 1 || !s->current || req->hba_private != s->current ||
         (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
-        if (lsi_queue_tag(s, req->tag, len)) {
+        if (lsi_queue_req(s, req, len)) {
             return;
         }
     }
@@ -789,7 +782,8 @@ static void lsi_do_command(LSIState *s)
     assert(s->current == NULL);
     s->current = qemu_mallocz(sizeof(lsi_request));
     s->current->tag = s->select_tag;
-    s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun);
+    s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun,
+                                   s->current);
 
     n = scsi_req_enqueue(s->current->req, buf);
     if (n) {
index ad6a730be0fce732b94b16a931a0b677c3b28a6f..8b1a4122106e30d9a1e43bb19361ef660dd7e3c7 100644 (file)
@@ -131,7 +131,8 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
     return res;
 }
 
-SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun)
+SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
+                            uint32_t lun, void *hba_private)
 {
     SCSIRequest *req;
 
@@ -141,14 +142,16 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l
     req->dev = d;
     req->tag = tag;
     req->lun = lun;
+    req->hba_private = hba_private;
     req->status = -1;
     trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
     return req;
 }
 
-SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun)
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                          void *hba_private)
 {
-    return d->info->alloc_req(d, tag, lun);
+    return d->info->alloc_req(d, tag, lun, hba_private);
 }
 
 uint8_t *scsi_req_get_buf(SCSIRequest *req)
index a8c7372d3e331e5b0bc067f22d2a0cfe5fc7df4d..05d14ab2fd4f83a82acec10be9ae0877e35f56ea 100644 (file)
@@ -81,13 +81,13 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
 static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
 
 static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
-        uint32_t lun)
+                                     uint32_t lun, void *hba_private)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
     SCSIRequest *req;
     SCSIDiskReq *r;
 
-    req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
+    req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun, hba_private);
     r = DO_UPCAST(SCSIDiskReq, req, req);
     r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
     return req;
@@ -398,7 +398,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
                     "buffer size %zd\n", req->cmd.xfer);
             pages = buflen++;
             outbuf[buflen++] = 0x00; // list of supported pages (this page)
-            outbuf[buflen++] = 0x80; // unit serial number
+            if (s->serial)
+                outbuf[buflen++] = 0x80; // unit serial number
             outbuf[buflen++] = 0x83; // device identification
             if (s->drive_kind == SCSI_HD) {
                 outbuf[buflen++] = 0xb0; // block limits
@@ -409,8 +410,14 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         }
         case 0x80: /* Device serial number, optional */
         {
-            int l = strlen(s->serial);
+            int l;
 
+            if (!s->serial) {
+                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
+                return -1;
+            }
+
+            l = strlen(s->serial);
             if (l > req->cmd.xfer)
                 l = req->cmd.xfer;
             if (l > 20)
@@ -1007,7 +1014,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
 
     command = buf[0];
     outbuf = (uint8_t *)r->iov.iov_base;
-    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
+    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
 
     if (scsi_req_parse(&r->req, buf) != 0) {
         BADF("Unsupported command length, command %x\n", command);
@@ -1203,7 +1210,9 @@ static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
     if (!s->serial) {
         /* try to fall back to value set with legacy -drive serial=... */
         dinfo = drive_get_by_blockdev(s->bs);
-        s->serial = qemu_strdup(*dinfo->serial ? dinfo->serial : "0");
+        if (*dinfo->serial) {
+            s->serial = qemu_strdup(dinfo->serial);
+        }
     }
 
     if (!s->version) {
index 8e59c7ee897bace4732589b78f712b5806e77302..90345a714f923503fcbbd9867c2e121075d0b15f 100644 (file)
@@ -96,11 +96,12 @@ static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
     return size;
 }
 
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                                     void *hba_private)
 {
     SCSIRequest *req;
 
-    req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun);
+    req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun, hba_private);
     return req;
 }
 
index c1dca35b8672af8358b5ba0157b47a1bfbf4213c..6b15bbc2cd8d6a118e3859d0db54e5af7dd86c00 100644 (file)
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -43,6 +43,7 @@ struct SCSIRequest {
     } cmd;
     BlockDriverAIOCB  *aiocb;
     bool enqueued;
+    void *hba_private;
     QTAILQ_ENTRY(SCSIRequest) next;
 };
 
@@ -67,7 +68,8 @@ struct SCSIDeviceInfo {
     DeviceInfo qdev;
     scsi_qdev_initfn init;
     void (*destroy)(SCSIDevice *s);
-    SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun);
+    SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
+                              void *hba_private);
     void (*free_req)(SCSIRequest *req);
     int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
     void (*read_data)(SCSIRequest *req);
@@ -138,8 +140,10 @@ extern const struct SCSISense sense_code_LUN_FAILURE;
 int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed);
 int scsi_sense_valid(SCSISense sense);
 
-SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
-SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun);
+SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
+                            uint32_t lun, void *hba_private);
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                          void *hba_private);
 int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf);
 void scsi_req_free(SCSIRequest *req);
 SCSIRequest *scsi_req_ref(SCSIRequest *req);
index 1c901ef6ebfb78fc56e102d7d9cfc03a9d76dde6..646b1e3caf8547fa6a830bc1b1c21bfb6da2602b 100644 (file)
@@ -121,7 +121,7 @@ static struct vscsi_req *vscsi_get_req(VSCSIState *s)
     return NULL;
 }
 
-static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
+static void vscsi_put_req(vscsi_req *req)
 {
     if (req->sreq != NULL) {
         scsi_req_unref(req->sreq);
@@ -130,15 +130,6 @@ static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
     req->active = 0;
 }
 
-static vscsi_req *vscsi_find_req(VSCSIState *s, SCSIRequest *req)
-{
-    uint32_t tag = req->tag;
-    if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) {
-        return NULL;
-    }
-    return &s->reqs[tag];
-}
-
 static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
 {
     /* XXX Figure that one out properly ! This is crackpot */
@@ -454,7 +445,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
     if (n) {
         req->senselen = n;
         vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
-        vscsi_put_req(s, req);
+        vscsi_put_req(req);
         return;
     }
 
@@ -483,7 +474,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
 static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
 {
     VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
-    vscsi_req *req = vscsi_find_req(s, sreq);
+    vscsi_req *req = sreq->hba_private;
     uint8_t *buf;
     int rc = 0;
 
@@ -531,7 +522,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
 static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
 {
     VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
-    vscsi_req *req = vscsi_find_req(s, sreq);
+    vscsi_req *req = sreq->hba_private;
     int32_t res_in = 0, res_out = 0;
 
     dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n",
@@ -563,15 +554,14 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
         }
     }
     vscsi_send_rsp(s, req, 0, res_in, res_out);
-    vscsi_put_req(s, req);
+    vscsi_put_req(req);
 }
 
 static void vscsi_request_cancelled(SCSIRequest *sreq)
 {
-    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
-    vscsi_req *req = vscsi_find_req(s, sreq);
+    vscsi_req *req = sreq->hba_private;
 
-    vscsi_put_req(s, req);
+    vscsi_put_req(req);
 }
 
 static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
@@ -659,7 +649,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
     }
 
     req->lun = lun;
-    req->sreq = scsi_req_new(sdev, req->qtag, lun);
+    req->sreq = scsi_req_new(sdev, req->qtag, lun, req);
     n = scsi_req_enqueue(req->sreq, srp->cmd.cdb);
 
     dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
@@ -858,7 +848,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
     }
 
     if (done) {
-        vscsi_put_req(s, req);
+        vscsi_put_req(req);
     }
 }
 
index 86582cc723b881d728cf8285a1f2b5e8ab2d8c0e..bfea0968938d1d28023c430d6810959d3d3fc64b 100644 (file)
@@ -216,10 +216,6 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
     MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
     USBPacket *p = s->packet;
 
-    if (req->tag != s->tag) {
-        fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
-    }
-
     assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
     s->scsi_len = len;
     s->scsi_buf = scsi_req_get_buf(req);
@@ -241,9 +237,6 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
     MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
     USBPacket *p = s->packet;
 
-    if (req->tag != s->tag) {
-        fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
-    }
     DPRINTF("Command complete %d\n", status);
     s->residue = s->data_len;
     s->result = status != 0;
@@ -387,7 +380,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                     s->tag, cbw.flags, cbw.cmd_len, s->data_len);
             s->residue = 0;
             s->scsi_len = 0;
-            s->req = scsi_req_new(s->scsi_dev, s->tag, 0);
+            s->req = scsi_req_new(s->scsi_dev, s->tag, 0, NULL);
             scsi_req_enqueue(s->req, cbw.cmd);
             /* ??? Should check that USB and SCSI data transfer
                directions match.  */
index 6997e02dcf083a4aef4c39572c5af242eedf3512..a32cc019b09b88664e90e9d91a22e8161ae391dd 100644 (file)
@@ -657,7 +657,7 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
 
         /* copy in packet.  ugh */
         len = iov_from_buf(sg, elem.in_num,
-                           buf + offset, size - offset);
+                           buf + offset, 0, size - offset);
         total += len;
         offset += len;
         /* If buffers can't be merged, at this point we
index 6d73386441c8a0d1b92fb591c0c3e413a02a63cb..bdc760c36e9dced1ed16ffd6109e4ddbd7bafe98 100644 (file)
@@ -104,7 +104,7 @@ static size_t write_to_port(VirtIOSerialPort *port,
         }
 
         len = iov_from_buf(elem.in_sg, elem.in_num,
-                           buf + offset, size - offset);
+                           buf + offset, 0, size - offset);
         offset += len;
 
         virtqueue_push(vq, &elem, len);
diff --git a/iov.c b/iov.c
index 588cd042881b5af2b808094a793f868f2a01bf6e..1e027914d4862c15255f91706d41f22b894d7d3f 100644 (file)
--- a/iov.c
+++ b/iov.c
 
 #include "iov.h"
 
-size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt,
-                    const void *buf, size_t size)
+size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
+                    const void *buf, size_t iov_off, size_t size)
 {
-    size_t offset;
+    size_t iovec_off, buf_off;
     unsigned int i;
 
-    offset = 0;
-    for (i = 0; offset < size && i < iovcnt; i++) {
-        size_t len;
+    iovec_off = 0;
+    buf_off = 0;
+    for (i = 0; i < iov_cnt && size; i++) {
+        if (iov_off < (iovec_off + iov[i].iov_len)) {
+            size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off, size);
 
-        len = MIN(iov[i].iov_len, size - offset);
+            memcpy(iov[i].iov_base + (iov_off - iovec_off), buf + buf_off, len);
 
-        memcpy(iov[i].iov_base, buf + offset, len);
-        offset += len;
+            buf_off += len;
+            iov_off += len;
+            size -= len;
+        }
+        iovec_off += iov[i].iov_len;
     }
-    return offset;
+    return buf_off;
 }
 
-size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
-                  void *buf, size_t offset, size_t size)
+size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+                  void *buf, size_t iov_off, size_t size)
 {
     uint8_t *ptr;
-    size_t iov_off, buf_off;
+    size_t iovec_off, buf_off;
     unsigned int i;
 
     ptr = buf;
-    iov_off = 0;
+    iovec_off = 0;
     buf_off = 0;
-    for (i = 0; i < iovcnt && size; i++) {
-        if (offset < (iov_off + iov[i].iov_len)) {
-            size_t len = MIN((iov_off + iov[i].iov_len) - offset , size);
+    for (i = 0; i < iov_cnt && size; i++) {
+        if (iov_off < (iovec_off + iov[i].iov_len)) {
+            size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
 
-            memcpy(ptr + buf_off, iov[i].iov_base + (offset - iov_off), len);
+            memcpy(ptr + buf_off, iov[i].iov_base + (iov_off - iovec_off), len);
 
             buf_off += len;
-            offset += len;
+            iov_off += len;
             size -= len;
         }
-        iov_off += iov[i].iov_len;
+        iovec_off += iov[i].iov_len;
     }
     return buf_off;
 }
 
-size_t iov_size(const struct iovec *iov, const unsigned int iovcnt)
+size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
 {
     size_t len;
     unsigned int i;
 
     len = 0;
-    for (i = 0; i < iovcnt; i++) {
+    for (i = 0; i < iov_cnt; i++) {
         len += iov[i].iov_len;
     }
     return len;
diff --git a/iov.h b/iov.h
index 60a85470bd7336f932fbd52bdf7fc87183c9420c..110f67ab530f8b95faaff0adfe6f78c6de133f1c 100644 (file)
--- a/iov.h
+++ b/iov.h
@@ -12,8 +12,8 @@
 
 #include "qemu-common.h"
 
-size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt,
-                    const void *buf, size_t size);
-size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
-                  void *buf, size_t offset, size_t size);
-size_t iov_size(const struct iovec *iov, const unsigned int iovcnt);
+size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
+                    const void *buf, size_t iov_off, size_t size);
+size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+                  void *buf, size_t iov_off, size_t size);
+size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
index c63741c6b1c2983156815690e6b8520197f42520..93d20c6cf82d8e9bb8b77e28cc902d685d17398d 100644 (file)
@@ -23,6 +23,7 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "index",
             .type = QEMU_OPT_NUMBER,
+            .help = "index number",
         },{
             .name = "cyls",
             .type = QEMU_OPT_NUMBER,
@@ -46,6 +47,7 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "snapshot",
             .type = QEMU_OPT_BOOL,
+            .help = "enable/disable snapshot mode",
         },{
             .name = "file",
             .type = QEMU_OPT_STRING,
@@ -65,12 +67,15 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "serial",
             .type = QEMU_OPT_STRING,
+            .help = "disk serial number",
         },{
             .name = "rerror",
             .type = QEMU_OPT_STRING,
+            .help = "read error action",
         },{
             .name = "werror",
             .type = QEMU_OPT_STRING,
+            .help = "write error action",
         },{
             .name = "addr",
             .type = QEMU_OPT_STRING,
@@ -78,6 +83,7 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "readonly",
             .type = QEMU_OPT_BOOL,
+            .help = "open drive file as read-only",
         },
         { /* end of list */ }
     },
index 2b70618c7040fe2f8766d3ad36743aed031f1771..1299e83ef2ec2ff267662b1f0d1b784d06b4e165 100644 (file)
@@ -30,7 +30,7 @@ ETEXI
 DEF("convert", img_convert,
     "convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
 STEXI
-@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+@item convert [-c] [-p] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 ETEXI
 
 DEF("info", img_info,
@@ -48,7 +48,7 @@ ETEXI
 DEF("rebase", img_rebase,
     "rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
 STEXI
-@item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
+@item rebase [-f @var{fmt}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
 ETEXI
 
 DEF("resize", img_resize,
index 54137a4e922aed1e7d63540da105d1ef1776a9dd..b205e98dd2513a7fd32bf2f99be197f73d011cc0 100644 (file)
@@ -1024,35 +1024,6 @@ out:
     return 0;
 }
 
-#ifdef _WIN32
-static int64_t get_allocated_file_size(const char *filename)
-{
-    typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
-    get_compressed_t get_compressed;
-    struct _stati64 st;
-
-    /* WinNT support GetCompressedFileSize to determine allocate size */
-    get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
-    if (get_compressed) {
-       DWORD high, low;
-       low = get_compressed(filename, &high);
-       if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
-           return (((int64_t) high) << 32) + low;
-    }
-
-    if (_stati64(filename, &st) < 0)
-        return -1;
-    return st.st_size;
-}
-#else
-static int64_t get_allocated_file_size(const char *filename)
-{
-    struct stat st;
-    if (stat(filename, &st) < 0)
-        return -1;
-    return (int64_t)st.st_blocks * 512;
-}
-#endif
 
 static void dump_snapshots(BlockDriverState *bs)
 {
@@ -1112,7 +1083,7 @@ static int img_info(int argc, char **argv)
     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
     bdrv_get_geometry(bs, &total_sectors);
     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
-    allocated_size = get_allocated_file_size(filename);
+    allocated_size = bdrv_get_allocated_file_size(bs);
     if (allocated_size < 0) {
         snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
     } else {
index 526474c112f0761b7e8eef2ad6ba2bbf3fcdb470..495a1b66954b0eea22f74d0bbe57c22806a3a0aa 100644 (file)
@@ -38,6 +38,8 @@ by the used format or see the format descriptions below for details.
 indicates that target image must be compressed (qcow format only)
 @item -h
 with or without a command shows help and lists the supported formats
+@item -p
+display progress bar (convert and rebase commands only)
 @end table
 
 Parameters to snapshot subcommand:
@@ -84,7 +86,7 @@ it doesn't need to be specified separately in this case.
 
 Commit the changes recorded in @var{filename} in its base image.
 
-@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+@item convert [-c] [-p] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 
 Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename}
 using format @var{output_fmt}. It can be optionally compressed (@code{-c}
@@ -114,7 +116,7 @@ they are displayed too.
 
 List, apply, create or delete snapshots in image @var{filename}.
 
-@item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
+@item rebase [-f @var{fmt}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
 
 Changes the backing file of an image. Only the formats @code{qcow2} and
 @code{qed} support changing the backing file.
index dd4ebf537a0196c9567ada074e7140b2e005fb17..a553d0c98dca4ee3960632e01dd220bbc5e9e3c2 100644 (file)
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -20,7 +20,7 @@
 
 #define VERSION        "0.0.1"
 
-#define CMD_NOFILE_OK  0x01
+#define CMD_NOFILE_OK   0x01
 
 char *progname;
 static BlockDriverState *bs;
@@ -35,16 +35,16 @@ static int misalign;
  */
 static int parse_pattern(const char *arg)
 {
-       char *endptr = NULL;
-       long pattern;
+    char *endptr = NULL;
+    long pattern;
 
-       pattern = strtol(arg, &endptr, 0);
-       if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
-               printf("%s is not a valid pattern byte\n", arg);
-               return -1;
-       }
+    pattern = strtol(arg, &endptr, 0);
+    if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
+        printf("%s is not a valid pattern byte\n", arg);
+        return -1;
+    }
 
-       return pattern;
+    return pattern;
 }
 
 /*
@@ -54,70 +54,73 @@ static int parse_pattern(const char *arg)
  * that is specified on the command line.
  */
 
-#define MISALIGN_OFFSET                16
+#define MISALIGN_OFFSET     16
 static void *qemu_io_alloc(size_t len, int pattern)
 {
-       void *buf;
-
-       if (misalign)
-               len += MISALIGN_OFFSET;
-       buf = qemu_blockalign(bs, len);
-       memset(buf, pattern, len);
-       if (misalign)
-               buf += MISALIGN_OFFSET;
-       return buf;
+    void *buf;
+
+    if (misalign) {
+        len += MISALIGN_OFFSET;
+    }
+    buf = qemu_blockalign(bs, len);
+    memset(buf, pattern, len);
+    if (misalign) {
+        buf += MISALIGN_OFFSET;
+    }
+    return buf;
 }
 
 static void qemu_io_free(void *p)
 {
-       if (misalign)
-               p -= MISALIGN_OFFSET;
-       qemu_vfree(p);
+    if (misalign) {
+        p -= MISALIGN_OFFSET;
+    }
+    qemu_vfree(p);
 }
 
-static void
-dump_buffer(const void *buffer, int64_t offset, int len)
+static void dump_buffer(const void *buffer, int64_t offset, int len)
 {
-       int i, j;
-       const uint8_t *p;
-
-       for (i = 0, p = buffer; i < len; i += 16) {
-               const uint8_t *s = p;
-
-                printf("%08" PRIx64 ":  ", offset + i);
-               for (j = 0; j < 16 && i + j < len; j++, p++)
-                       printf("%02x ", *p);
-               printf(" ");
-               for (j = 0; j < 16 && i + j < len; j++, s++) {
-                       if (isalnum(*s))
-                               printf("%c", *s);
-                       else
-                               printf(".");
-               }
-               printf("\n");
-       }
+    int i, j;
+    const uint8_t *p;
+
+    for (i = 0, p = buffer; i < len; i += 16) {
+        const uint8_t *s = p;
+
+        printf("%08" PRIx64 ":  ", offset + i);
+        for (j = 0; j < 16 && i + j < len; j++, p++) {
+            printf("%02x ", *p);
+        }
+        printf(" ");
+        for (j = 0; j < 16 && i + j < len; j++, s++) {
+            if (isalnum(*s)) {
+                printf("%c", *s);
+            } else {
+                printf(".");
+            }
+        }
+        printf("\n");
+    }
 }
 
-static void
-print_report(const char *op, struct timeval *t, int64_t offset,
-               int count, int total, int cnt, int Cflag)
+static void print_report(const char *op, struct timeval *t, int64_t offset,
+                         int count, int total, int cnt, int Cflag)
 {
-       char s1[64], s2[64], ts[64];
-
-       timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
-       if (!Cflag) {
-               cvtstr((double)total, s1, sizeof(s1));
-               cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
-                printf("%s %d/%d bytes at offset %" PRId64 "\n",
-                       op, total, count, offset);
-               printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
-                       s1, cnt, ts, s2, tdiv((double)cnt, *t));
-       } else {/* bytes,ops,time,bytes/sec,ops/sec */
-               printf("%d,%d,%s,%.3f,%.3f\n",
-                       total, cnt, ts,
-                       tdiv((double)total, *t),
-                       tdiv((double)cnt, *t));
-       }
+    char s1[64], s2[64], ts[64];
+
+    timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
+    if (!Cflag) {
+        cvtstr((double)total, s1, sizeof(s1));
+        cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
+        printf("%s %d/%d bytes at offset %" PRId64 "\n",
+               op, total, count, offset);
+        printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
+               s1, cnt, ts, s2, tdiv((double)cnt, *t));
+    } else {/* bytes,ops,time,bytes/sec,ops/sec */
+        printf("%d,%d,%s,%.3f,%.3f\n",
+            total, cnt, ts,
+            tdiv((double)total, *t),
+            tdiv((double)cnt, *t));
+    }
 }
 
 /*
@@ -127,192 +130,200 @@ print_report(const char *op, struct timeval *t, int64_t offset,
 static void *
 create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
 {
-       size_t *sizes = calloc(nr_iov, sizeof(size_t));
-       size_t count = 0;
-       void *buf = NULL;
-       void *p;
-       int i;
-
-       for (i = 0; i < nr_iov; i++) {
-               char *arg = argv[i];
-                int64_t len;
-
-               len = cvtnum(arg);
-               if (len < 0) {
-                       printf("non-numeric length argument -- %s\n", arg);
-                       goto fail;
-               }
-
-               /* should be SIZE_T_MAX, but that doesn't exist */
-               if (len > INT_MAX) {
-                       printf("too large length argument -- %s\n", arg);
-                       goto fail;
-               }
-
-               if (len & 0x1ff) {
-                        printf("length argument %" PRId64
-                               " is not sector aligned\n", len);
-                       goto fail;
-               }
-
-               sizes[i] = len;
-               count += len;
-       }
-
-       qemu_iovec_init(qiov, nr_iov);
-
-       buf = p = qemu_io_alloc(count, pattern);
-
-       for (i = 0; i < nr_iov; i++) {
-               qemu_iovec_add(qiov, p, sizes[i]);
-               p += sizes[i];
-       }
+    size_t *sizes = calloc(nr_iov, sizeof(size_t));
+    size_t count = 0;
+    void *buf = NULL;
+    void *p;
+    int i;
+
+    for (i = 0; i < nr_iov; i++) {
+        char *arg = argv[i];
+        int64_t len;
+
+        len = cvtnum(arg);
+        if (len < 0) {
+            printf("non-numeric length argument -- %s\n", arg);
+            goto fail;
+        }
+
+        /* should be SIZE_T_MAX, but that doesn't exist */
+        if (len > INT_MAX) {
+            printf("too large length argument -- %s\n", arg);
+            goto fail;
+        }
+
+        if (len & 0x1ff) {
+            printf("length argument %" PRId64
+                   " is not sector aligned\n", len);
+            goto fail;
+        }
+
+        sizes[i] = len;
+        count += len;
+    }
+
+    qemu_iovec_init(qiov, nr_iov);
+
+    buf = p = qemu_io_alloc(count, pattern);
+
+    for (i = 0; i < nr_iov; i++) {
+        qemu_iovec_add(qiov, p, sizes[i]);
+        p += sizes[i];
+    }
 
 fail:
-       free(sizes);
-       return buf;
+    free(sizes);
+    return buf;
 }
 
 static int do_read(char *buf, int64_t offset, int count, int *total)
 {
-       int ret;
+    int ret;
 
-       ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
-       if (ret < 0)
-               return ret;
-       *total = count;
-       return 1;
+    ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    if (ret < 0) {
+        return ret;
+    }
+    *total = count;
+    return 1;
 }
 
 static int do_write(char *buf, int64_t offset, int count, int *total)
 {
-       int ret;
+    int ret;
 
-       ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
-       if (ret < 0)
-               return ret;
-       *total = count;
-       return 1;
+    ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    if (ret < 0) {
+        return ret;
+    }
+    *total = count;
+    return 1;
 }
 
 static int do_pread(char *buf, int64_t offset, int count, int *total)
 {
-       *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
-       if (*total < 0)
-               return *total;
-       return 1;
+    *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
 }
 
 static int do_pwrite(char *buf, int64_t offset, int count, int *total)
 {
-       *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
-       if (*total < 0)
-               return *total;
-       return 1;
+    *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
 }
 
 static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
 {
-       *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
-       if (*total < 0)
-               return *total;
-       return 1;
+    *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
 }
 
 static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
 {
-       *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
-       if (*total < 0)
-               return *total;
-       return 1;
+    *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
 }
 
 #define NOT_DONE 0x7fffffff
 static void aio_rw_done(void *opaque, int ret)
 {
-       *(int *)opaque = ret;
+    *(int *)opaque = ret;
 }
 
 static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
 {
-       BlockDriverAIOCB *acb;
-       int async_ret = NOT_DONE;
+    BlockDriverAIOCB *acb;
+    int async_ret = NOT_DONE;
 
-       acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
-                            aio_rw_done, &async_ret);
-       if (!acb)
-               return -EIO;
-
-       while (async_ret == NOT_DONE)
-               qemu_aio_wait();
+    acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
+                         aio_rw_done, &async_ret);
+    if (!acb) {
+        return -EIO;
+    }
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
 
-       *total = qiov->size;
-       return async_ret < 0 ? async_ret : 1;
+    *total = qiov->size;
+    return async_ret < 0 ? async_ret : 1;
 }
 
 static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
 {
-       BlockDriverAIOCB *acb;
-       int async_ret = NOT_DONE;
+    BlockDriverAIOCB *acb;
+    int async_ret = NOT_DONE;
 
-       acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
-                             aio_rw_done, &async_ret);
-       if (!acb)
-               return -EIO;
+    acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
+                          aio_rw_done, &async_ret);
+    if (!acb) {
+        return -EIO;
+    }
 
-       while (async_ret == NOT_DONE)
-               qemu_aio_wait();
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
 
-       *total = qiov->size;
-       return async_ret < 0 ? async_ret : 1;
+    *total = qiov->size;
+    return async_ret < 0 ? async_ret : 1;
 }
 
 struct multiwrite_async_ret {
-       int num_done;
-       int error;
+    int num_done;
+    int error;
 };
 
 static void multiwrite_cb(void *opaque, int ret)
 {
-       struct multiwrite_async_ret *async_ret = opaque;
+    struct multiwrite_async_ret *async_ret = opaque;
 
-       async_ret->num_done++;
-       if (ret < 0) {
-               async_ret->error = ret;
-       }
+    async_ret->num_done++;
+    if (ret < 0) {
+        async_ret->error = ret;
+    }
 }
 
 static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
 {
-       int i, ret;
-       struct multiwrite_async_ret async_ret = {
-               .num_done = 0,
-               .error = 0,
-       };
-
-       *total = 0;
-       for (i = 0; i < num_reqs; i++) {
-               reqs[i].cb = multiwrite_cb;
-               reqs[i].opaque = &async_ret;
-               *total += reqs[i].qiov->size;
-       }
-
-       ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
-       if (ret < 0) {
-               return ret;
-       }
-
-       while (async_ret.num_done < num_reqs) {
-               qemu_aio_wait();
-       }
-
-       return async_ret.error < 0 ? async_ret.error : 1;
+    int i, ret;
+    struct multiwrite_async_ret async_ret = {
+        .num_done = 0,
+        .error = 0,
+    };
+
+    *total = 0;
+    for (i = 0; i < num_reqs; i++) {
+        reqs[i].cb = multiwrite_cb;
+        reqs[i].opaque = &async_ret;
+        *total += reqs[i].qiov->size;
+    }
+
+    ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    while (async_ret.num_done < num_reqs) {
+        qemu_aio_wait();
+    }
+
+    return async_ret.error < 0 ? async_ret.error : 1;
 }
 
-static void
-read_help(void)
+static void read_help(void)
 {
-       printf(
+    printf(
 "\n"
 " reads a range of bytes from the given offset\n"
 "\n"
@@ -335,94 +346,95 @@ read_help(void)
 static int read_f(int argc, char **argv);
 
 static const cmdinfo_t read_cmd = {
-       .name           = "read",
-       .altname        = "r",
-       .cfunc          = read_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
-       .oneline        = "reads a number of bytes at a specified offset",
-       .help           = read_help,
+    .name       = "read",
+    .altname    = "r",
+    .cfunc      = read_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
+    .oneline    = "reads a number of bytes at a specified offset",
+    .help       = read_help,
 };
 
-static int
-read_f(int argc, char **argv)
+static int read_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
-       int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
-       int c, cnt;
-       char *buf;
-       int64_t offset;
-       int count;
-        /* Some compilers get confused and warn if this is not initialized.  */
-        int total = 0;
-       int pattern = 0, pattern_offset = 0, pattern_count = 0;
-
-       while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
-               switch (c) {
-               case 'b':
-                       bflag = 1;
-                       break;
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'l':
-                       lflag = 1;
-                       pattern_count = cvtnum(optarg);
-                       if (pattern_count < 0) {
-                               printf("non-numeric length argument -- %s\n", optarg);
-                               return 0;
-                       }
-                       break;
-               case 'p':
-                       pflag = 1;
-                       break;
-               case 'P':
-                       Pflag = 1;
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               case 's':
-                       sflag = 1;
-                       pattern_offset = cvtnum(optarg);
-                       if (pattern_offset < 0) {
-                               printf("non-numeric length argument -- %s\n", optarg);
-                               return 0;
-                       }
-                       break;
-               case 'v':
-                       vflag = 1;
-                       break;
-               default:
-                       return command_usage(&read_cmd);
-               }
-       }
-
-       if (optind != argc - 2)
-               return command_usage(&read_cmd);
-
-       if (bflag && pflag) {
-               printf("-b and -p cannot be specified at the same time\n");
-               return 0;
-       }
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       optind++;
-       count = cvtnum(argv[optind]);
-       if (count < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
+    struct timeval t1, t2;
+    int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
+    int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    int count;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int pattern = 0, pattern_offset = 0, pattern_count = 0;
+
+    while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
+        switch (c) {
+        case 'b':
+            bflag = 1;
+            break;
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'l':
+            lflag = 1;
+            pattern_count = cvtnum(optarg);
+            if (pattern_count < 0) {
+                printf("non-numeric length argument -- %s\n", optarg);
+                return 0;
+            }
+            break;
+        case 'p':
+            pflag = 1;
+            break;
+        case 'P':
+            Pflag = 1;
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 's':
+            sflag = 1;
+            pattern_offset = cvtnum(optarg);
+            if (pattern_offset < 0) {
+                printf("non-numeric length argument -- %s\n", optarg);
+                return 0;
+            }
+            break;
+        case 'v':
+            vflag = 1;
+            break;
+        default:
+            return command_usage(&read_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&read_cmd);
+    }
+
+    if (bflag && pflag) {
+        printf("-b and -p cannot be specified at the same time\n");
+        return 0;
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
 
     if (!Pflag && (lflag || sflag)) {
         return command_usage(&read_cmd);
@@ -437,66 +449,68 @@ read_f(int argc, char **argv)
         return 0;
     }
 
-       if (!pflag)
-               if (offset & 0x1ff) {
-                        printf("offset %" PRId64 " is not sector aligned\n",
-                               offset);
-                       return 0;
-
-               if (count & 0x1ff) {
-                       printf("count %d is not sector aligned\n",
-                               count);
-                       return 0;
-               }
-       }
-
-       buf = qemu_io_alloc(count, 0xab);
-
-       gettimeofday(&t1, NULL);
-       if (pflag)
-               cnt = do_pread(buf, offset, count, &total);
-       else if (bflag)
-               cnt = do_load_vmstate(buf, offset, count, &total);
-       else
-               cnt = do_read(buf, offset, count, &total);
-       gettimeofday(&t2, NULL);
-
-       if (cnt < 0) {
-               printf("read failed: %s\n", strerror(-cnt));
-               goto out;
-       }
-
-       if (Pflag) {
-               void* cmp_buf = malloc(pattern_count);
-               memset(cmp_buf, pattern, pattern_count);
-               if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
-                       printf("Pattern verification failed at offset %"
-                               PRId64 ", %d bytes\n",
-                               offset + pattern_offset, pattern_count);
-               }
-               free(cmp_buf);
-       }
-
-       if (qflag)
-               goto out;
-
-        if (vflag)
-               dump_buffer(buf, offset, count);
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("read", &t2, offset, count, total, cnt, Cflag);
+    if (!pflag) {
+        if (offset & 0x1ff) {
+            printf("offset %" PRId64 " is not sector aligned\n",
+                   offset);
+            return 0;
+        }
+        if (count & 0x1ff) {
+            printf("count %d is not sector aligned\n",
+                   count);
+            return 0;
+        }
+    }
+
+    buf = qemu_io_alloc(count, 0xab);
+
+    gettimeofday(&t1, NULL);
+    if (pflag) {
+        cnt = do_pread(buf, offset, count, &total);
+    } else if (bflag) {
+        cnt = do_load_vmstate(buf, offset, count, &total);
+    } else {
+        cnt = do_read(buf, offset, count, &total);
+    }
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("read failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (Pflag) {
+        void *cmp_buf = malloc(pattern_count);
+        memset(cmp_buf, pattern, pattern_count);
+        if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %d bytes\n",
+                   offset + pattern_offset, pattern_count);
+        }
+        free(cmp_buf);
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    if (vflag) {
+        dump_buffer(buf, offset, count);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("read", &t2, offset, count, total, cnt, Cflag);
 
 out:
-       qemu_io_free(buf);
+    qemu_io_free(buf);
 
-       return 0;
+    return 0;
 }
 
-static void
-readv_help(void)
+static void readv_help(void)
 {
-       printf(
+    printf(
 "\n"
 " reads a range of bytes from the given offset into multiple buffers\n"
 "\n"
@@ -516,111 +530,112 @@ readv_help(void)
 static int readv_f(int argc, char **argv);
 
 static const cmdinfo_t readv_cmd = {
-       .name           = "readv",
-       .cfunc          = readv_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cqv] [-P pattern ] off len [len..]",
-       .oneline        = "reads a number of bytes at a specified offset",
-       .help           = readv_help,
+    .name       = "readv",
+    .cfunc      = readv_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cqv] [-P pattern ] off len [len..]",
+    .oneline    = "reads a number of bytes at a specified offset",
+    .help       = readv_help,
 };
 
-static int
-readv_f(int argc, char **argv)
+static int readv_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, qflag = 0, vflag = 0;
-       int c, cnt;
-       char *buf;
-       int64_t offset;
-        /* Some compilers get confused and warn if this is not initialized.  */
-        int total = 0;
-       int nr_iov;
-       QEMUIOVector qiov;
-       int pattern = 0;
-       int Pflag = 0;
-
-       while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
-               switch (c) {
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'P':
-                       Pflag = 1;
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               case 'v':
-                       vflag = 1;
-                       break;
-               default:
-                       return command_usage(&readv_cmd);
-               }
-       }
-
-       if (optind > argc - 2)
-               return command_usage(&readv_cmd);
-
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-       optind++;
-
-       if (offset & 0x1ff) {
-                printf("offset %" PRId64 " is not sector aligned\n",
-                       offset);
-               return 0;
-       }
-
-       nr_iov = argc - optind;
-       buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
-
-       gettimeofday(&t1, NULL);
-       cnt = do_aio_readv(&qiov, offset, &total);
-       gettimeofday(&t2, NULL);
-
-       if (cnt < 0) {
-               printf("readv failed: %s\n", strerror(-cnt));
-               goto out;
-       }
-
-       if (Pflag) {
-               void* cmp_buf = malloc(qiov.size);
-               memset(cmp_buf, pattern, qiov.size);
-               if (memcmp(buf, cmp_buf, qiov.size)) {
-                       printf("Pattern verification failed at offset %"
-                               PRId64 ", %zd bytes\n",
-                               offset, qiov.size);
-               }
-               free(cmp_buf);
-       }
-
-       if (qflag)
-               goto out;
-
-        if (vflag)
-               dump_buffer(buf, offset, qiov.size);
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0, vflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    QEMUIOVector qiov;
+    int pattern = 0;
+    int Pflag = 0;
+
+    while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'P':
+            Pflag = 1;
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'v':
+            vflag = 1;
+            break;
+        default:
+            return command_usage(&readv_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&readv_cmd);
+    }
+
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+    optind++;
+
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
+
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_readv(&qiov, offset, &total);
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("readv failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (Pflag) {
+        void *cmp_buf = malloc(qiov.size);
+        memset(cmp_buf, pattern, qiov.size);
+        if (memcmp(buf, cmp_buf, qiov.size)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %zd bytes\n", offset, qiov.size);
+        }
+        free(cmp_buf);
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    if (vflag) {
+        dump_buffer(buf, offset, qiov.size);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
 
 out:
-       qemu_io_free(buf);
-       return 0;
+    qemu_io_free(buf);
+    return 0;
 }
 
-static void
-write_help(void)
+static void write_help(void)
 {
-       printf(
+    printf(
 "\n"
 " writes a range of bytes from the given offset\n"
 "\n"
@@ -640,121 +655,124 @@ write_help(void)
 static int write_f(int argc, char **argv);
 
 static const cmdinfo_t write_cmd = {
-       .name           = "write",
-       .altname        = "w",
-       .cfunc          = write_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-abCpq] [-P pattern ] off len",
-       .oneline        = "writes a number of bytes at a specified offset",
-       .help           = write_help,
+    .name       = "write",
+    .altname    = "w",
+    .cfunc      = write_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-abCpq] [-P pattern ] off len",
+    .oneline    = "writes a number of bytes at a specified offset",
+    .help       = write_help,
 };
 
-static int
-write_f(int argc, char **argv)
+static int write_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
-       int c, cnt;
-       char *buf;
-       int64_t offset;
-       int count;
-        /* Some compilers get confused and warn if this is not initialized.  */
-        int total = 0;
-       int pattern = 0xcd;
-
-       while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
-               switch (c) {
-               case 'b':
-                       bflag = 1;
-                       break;
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'p':
-                       pflag = 1;
-                       break;
-               case 'P':
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               default:
-                       return command_usage(&write_cmd);
-               }
-       }
-
-       if (optind != argc - 2)
-               return command_usage(&write_cmd);
-
-       if (bflag && pflag) {
-               printf("-b and -p cannot be specified at the same time\n");
-               return 0;
-       }
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       optind++;
-       count = cvtnum(argv[optind]);
-       if (count < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       if (!pflag) {
-               if (offset & 0x1ff) {
-                        printf("offset %" PRId64 " is not sector aligned\n",
-                               offset);
-                       return 0;
-               }
-
-               if (count & 0x1ff) {
-                       printf("count %d is not sector aligned\n",
-                               count);
-                       return 0;
-               }
-       }
-
-       buf = qemu_io_alloc(count, pattern);
-
-       gettimeofday(&t1, NULL);
-       if (pflag)
-               cnt = do_pwrite(buf, offset, count, &total);
-       else if (bflag)
-               cnt = do_save_vmstate(buf, offset, count, &total);
-       else
-               cnt = do_write(buf, offset, count, &total);
-       gettimeofday(&t2, NULL);
-
-       if (cnt < 0) {
-               printf("write failed: %s\n", strerror(-cnt));
-               goto out;
-       }
-
-       if (qflag)
-               goto out;
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("wrote", &t2, offset, count, total, cnt, Cflag);
+    struct timeval t1, t2;
+    int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    int count;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int pattern = 0xcd;
+
+    while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
+        switch (c) {
+        case 'b':
+            bflag = 1;
+            break;
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'p':
+            pflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        default:
+            return command_usage(&write_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&write_cmd);
+    }
+
+    if (bflag && pflag) {
+        printf("-b and -p cannot be specified at the same time\n");
+        return 0;
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    if (!pflag) {
+        if (offset & 0x1ff) {
+            printf("offset %" PRId64 " is not sector aligned\n",
+                   offset);
+            return 0;
+        }
+
+        if (count & 0x1ff) {
+            printf("count %d is not sector aligned\n",
+                   count);
+            return 0;
+        }
+    }
+
+    buf = qemu_io_alloc(count, pattern);
+
+    gettimeofday(&t1, NULL);
+    if (pflag) {
+        cnt = do_pwrite(buf, offset, count, &total);
+    } else if (bflag) {
+        cnt = do_save_vmstate(buf, offset, count, &total);
+    } else {
+        cnt = do_write(buf, offset, count, &total);
+    }
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("write failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, offset, count, total, cnt, Cflag);
 
 out:
-       qemu_io_free(buf);
+    qemu_io_free(buf);
 
-       return 0;
+    return 0;
 }
 
 static void
 writev_help(void)
 {
-       printf(
+    printf(
 "\n"
 " writes a range of bytes from the given offset source from multiple buffers\n"
 "\n"
@@ -772,90 +790,91 @@ writev_help(void)
 static int writev_f(int argc, char **argv);
 
 static const cmdinfo_t writev_cmd = {
-       .name           = "writev",
-       .cfunc          = writev_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cq] [-P pattern ] off len [len..]",
-       .oneline        = "writes a number of bytes at a specified offset",
-       .help           = writev_help,
+    .name       = "writev",
+    .cfunc      = writev_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..]",
+    .oneline    = "writes a number of bytes at a specified offset",
+    .help       = writev_help,
 };
 
-static int
-writev_f(int argc, char **argv)
+static int writev_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, qflag = 0;
-       int c, cnt;
-       char *buf;
-       int64_t offset;
-        /* Some compilers get confused and warn if this is not initialized.  */
-        int total = 0;
-       int nr_iov;
-       int pattern = 0xcd;
-       QEMUIOVector qiov;
-
-       while ((c = getopt(argc, argv, "CqP:")) != EOF) {
-               switch (c) {
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               case 'P':
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               default:
-                       return command_usage(&writev_cmd);
-               }
-       }
-
-       if (optind > argc - 2)
-               return command_usage(&writev_cmd);
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-       optind++;
-
-       if (offset & 0x1ff) {
-                printf("offset %" PRId64 " is not sector aligned\n",
-                       offset);
-               return 0;
-       }
-
-       nr_iov = argc - optind;
-       buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
-
-       gettimeofday(&t1, NULL);
-       cnt = do_aio_writev(&qiov, offset, &total);
-       gettimeofday(&t2, NULL);
-
-       if (cnt < 0) {
-               printf("writev failed: %s\n", strerror(-cnt));
-               goto out;
-       }
-
-       if (qflag)
-               goto out;
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    int pattern = 0xcd;
+    QEMUIOVector qiov;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        default:
+            return command_usage(&writev_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&writev_cmd);
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+    optind++;
+
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
+
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_writev(&qiov, offset, &total);
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("writev failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
 out:
-       qemu_io_free(buf);
-       return 0;
+    qemu_io_free(buf);
+    return 0;
 }
 
-static void
-multiwrite_help(void)
+static void multiwrite_help(void)
 {
-       printf(
+    printf(
 "\n"
 " writes a range of bytes from the given offset source from multiple buffers,\n"
 " in a batch of requests that may be merged by qemu\n"
@@ -876,217 +895,215 @@ multiwrite_help(void)
 static int multiwrite_f(int argc, char **argv);
 
 static const cmdinfo_t multiwrite_cmd = {
-       .name           = "multiwrite",
-       .cfunc          = multiwrite_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
-       .oneline        = "issues multiple write requests at once",
-       .help           = multiwrite_help,
+    .name       = "multiwrite",
+    .cfunc      = multiwrite_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
+    .oneline    = "issues multiple write requests at once",
+    .help       = multiwrite_help,
 };
 
-static int
-multiwrite_f(int argc, char **argv)
+static int multiwrite_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, qflag = 0;
-       int c, cnt;
-       char **buf;
-       int64_t offset, first_offset = 0;
-       /* Some compilers get confused and warn if this is not initialized.  */
-       int total = 0;
-       int nr_iov;
-       int nr_reqs;
-       int pattern = 0xcd;
-       QEMUIOVector *qiovs;
-       int i;
-       BlockRequest *reqs;
-
-       while ((c = getopt(argc, argv, "CqP:")) != EOF) {
-               switch (c) {
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               case 'P':
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               default:
-                       return command_usage(&writev_cmd);
-               }
-       }
-
-       if (optind > argc - 2)
-               return command_usage(&writev_cmd);
-
-       nr_reqs = 1;
-       for (i = optind; i < argc; i++) {
-               if (!strcmp(argv[i], ";")) {
-                       nr_reqs++;
-               }
-       }
-
-       reqs = qemu_malloc(nr_reqs * sizeof(*reqs));
-       buf = qemu_malloc(nr_reqs * sizeof(*buf));
-       qiovs = qemu_malloc(nr_reqs * sizeof(*qiovs));
-
-       for (i = 0; i < nr_reqs; i++) {
-               int j;
-
-               /* Read the offset of the request */
-               offset = cvtnum(argv[optind]);
-               if (offset < 0) {
-                       printf("non-numeric offset argument -- %s\n", argv[optind]);
-                       return 0;
-               }
-               optind++;
-
-               if (offset & 0x1ff) {
-                       printf("offset %lld is not sector aligned\n",
-                               (long long)offset);
-                       return 0;
-               }
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, cnt;
+    char **buf;
+    int64_t offset, first_offset = 0;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    int nr_reqs;
+    int pattern = 0xcd;
+    QEMUIOVector *qiovs;
+    int i;
+    BlockRequest *reqs;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        default:
+            return command_usage(&writev_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&writev_cmd);
+    }
+
+    nr_reqs = 1;
+    for (i = optind; i < argc; i++) {
+        if (!strcmp(argv[i], ";")) {
+            nr_reqs++;
+        }
+    }
+
+    reqs = qemu_malloc(nr_reqs * sizeof(*reqs));
+    buf = qemu_malloc(nr_reqs * sizeof(*buf));
+    qiovs = qemu_malloc(nr_reqs * sizeof(*qiovs));
+
+    for (i = 0; i < nr_reqs; i++) {
+        int j;
+
+        /* Read the offset of the request */
+        offset = cvtnum(argv[optind]);
+        if (offset < 0) {
+            printf("non-numeric offset argument -- %s\n", argv[optind]);
+            return 0;
+        }
+        optind++;
+
+        if (offset & 0x1ff) {
+            printf("offset %lld is not sector aligned\n",
+                   (long long)offset);
+            return 0;
+        }
 
         if (i == 0) {
             first_offset = offset;
         }
 
-               /* Read lengths for qiov entries */
-               for (j = optind; j < argc; j++) {
-                       if (!strcmp(argv[j], ";")) {
-                               break;
-                       }
-               }
+        /* Read lengths for qiov entries */
+        for (j = optind; j < argc; j++) {
+            if (!strcmp(argv[j], ";")) {
+                break;
+            }
+        }
 
-               nr_iov = j - optind;
+        nr_iov = j - optind;
 
-               /* Build request */
-               reqs[i].qiov = &qiovs[i];
-               buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern);
-               reqs[i].sector = offset >> 9;
-               reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
+        /* Build request */
+        reqs[i].qiov = &qiovs[i];
+        buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern);
+        reqs[i].sector = offset >> 9;
+        reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
 
-               optind = j + 1;
+        optind = j + 1;
 
-               offset += reqs[i].qiov->size;
-               pattern++;
-       }
+        offset += reqs[i].qiov->size;
+        pattern++;
+    }
 
-       gettimeofday(&t1, NULL);
-       cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
-       gettimeofday(&t2, NULL);
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
+    gettimeofday(&t2, NULL);
 
-       if (cnt < 0) {
-               printf("aio_multiwrite failed: %s\n", strerror(-cnt));
-               goto out;
-       }
+    if (cnt < 0) {
+        printf("aio_multiwrite failed: %s\n", strerror(-cnt));
+        goto out;
+    }
 
-       if (qflag)
-               goto out;
+    if (qflag) {
+        goto out;
+    }
 
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
 out:
-       for (i = 0; i < nr_reqs; i++) {
-               qemu_io_free(buf[i]);
-               qemu_iovec_destroy(&qiovs[i]);
-       }
-       qemu_free(buf);
-       qemu_free(reqs);
-       qemu_free(qiovs);
-       return 0;
+    for (i = 0; i < nr_reqs; i++) {
+        qemu_io_free(buf[i]);
+        qemu_iovec_destroy(&qiovs[i]);
+    }
+    qemu_free(buf);
+    qemu_free(reqs);
+    qemu_free(qiovs);
+    return 0;
 }
 
 struct aio_ctx {
-       QEMUIOVector qiov;
-       int64_t offset;
-       char *buf;
-       int qflag;
-       int vflag;
-       int Cflag;
-       int Pflag;
-       int pattern;
-       struct timeval t1;
+    QEMUIOVector qiov;
+    int64_t offset;
+    char *buf;
+    int qflag;
+    int vflag;
+    int Cflag;
+    int Pflag;
+    int pattern;
+    struct timeval t1;
 };
 
-static void
-aio_write_done(void *opaque, int ret)
+static void aio_write_done(void *opaque, int ret)
 {
-       struct aio_ctx *ctx = opaque;
-       struct timeval t2;
+    struct aio_ctx *ctx = opaque;
+    struct timeval t2;
 
-       gettimeofday(&t2, NULL);
+    gettimeofday(&t2, NULL);
 
 
-       if (ret < 0) {
-               printf("aio_write failed: %s\n", strerror(-ret));
-               goto out;
-       }
+    if (ret < 0) {
+        printf("aio_write failed: %s\n", strerror(-ret));
+        goto out;
+    }
 
-       if (ctx->qflag) {
-               goto out;
-       }
+    if (ctx->qflag) {
+        goto out;
+    }
 
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, ctx->t1);
-       print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
-                    ctx->qiov.size, 1, ctx->Cflag);
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, ctx->t1);
+    print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
+                 ctx->qiov.size, 1, ctx->Cflag);
 out:
-       qemu_io_free(ctx->buf);
-       free(ctx);
+    qemu_io_free(ctx->buf);
+    free(ctx);
 }
 
-static void
-aio_read_done(void *opaque, int ret)
+static void aio_read_done(void *opaque, int ret)
 {
-       struct aio_ctx *ctx = opaque;
-       struct timeval t2;
-
-       gettimeofday(&t2, NULL);
-
-       if (ret < 0) {
-               printf("readv failed: %s\n", strerror(-ret));
-               goto out;
-       }
-
-       if (ctx->Pflag) {
-               void *cmp_buf = malloc(ctx->qiov.size);
-
-               memset(cmp_buf, ctx->pattern, ctx->qiov.size);
-               if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
-                       printf("Pattern verification failed at offset %"
-                               PRId64 ", %zd bytes\n",
-                               ctx->offset, ctx->qiov.size);
-               }
-               free(cmp_buf);
-       }
-
-       if (ctx->qflag) {
-               goto out;
-       }
-
-       if (ctx->vflag) {
-               dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
-       }
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, ctx->t1);
-       print_report("read", &t2, ctx->offset, ctx->qiov.size,
-                    ctx->qiov.size, 1, ctx->Cflag);
+    struct aio_ctx *ctx = opaque;
+    struct timeval t2;
+
+    gettimeofday(&t2, NULL);
+
+    if (ret < 0) {
+        printf("readv failed: %s\n", strerror(-ret));
+        goto out;
+    }
+
+    if (ctx->Pflag) {
+        void *cmp_buf = malloc(ctx->qiov.size);
+
+        memset(cmp_buf, ctx->pattern, ctx->qiov.size);
+        if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
+        }
+        free(cmp_buf);
+    }
+
+    if (ctx->qflag) {
+        goto out;
+    }
+
+    if (ctx->vflag) {
+        dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, ctx->t1);
+    print_report("read", &t2, ctx->offset, ctx->qiov.size,
+                 ctx->qiov.size, 1, ctx->Cflag);
 out:
-       qemu_io_free(ctx->buf);
-       free(ctx);
+    qemu_io_free(ctx->buf);
+    free(ctx);
 }
 
-static void
-aio_read_help(void)
+static void aio_read_help(void)
 {
-       printf(
+    printf(
 "\n"
 " asynchronously reads a range of bytes from the given offset\n"
 "\n"
@@ -1107,88 +1124,86 @@ aio_read_help(void)
 static int aio_read_f(int argc, char **argv);
 
 static const cmdinfo_t aio_read_cmd = {
-       .name           = "aio_read",
-       .cfunc          = aio_read_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cqv] [-P pattern ] off len [len..]",
-       .oneline        = "asynchronously reads a number of bytes",
-       .help           = aio_read_help,
+    .name       = "aio_read",
+    .cfunc      = aio_read_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cqv] [-P pattern ] off len [len..]",
+    .oneline    = "asynchronously reads a number of bytes",
+    .help       = aio_read_help,
 };
 
-static int
-aio_read_f(int argc, char **argv)
+static int aio_read_f(int argc, char **argv)
 {
-       int nr_iov, c;
-       struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
-       BlockDriverAIOCB *acb;
-
-       while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
-               switch (c) {
-               case 'C':
-                       ctx->Cflag = 1;
-                       break;
-               case 'P':
-                       ctx->Pflag = 1;
-                       ctx->pattern = parse_pattern(optarg);
-                       if (ctx->pattern < 0) {
-                                free(ctx);
-                               return 0;
-                        }
-                       break;
-               case 'q':
-                       ctx->qflag = 1;
-                       break;
-               case 'v':
-                       ctx->vflag = 1;
-                       break;
-               default:
-                       free(ctx);
-                       return command_usage(&aio_read_cmd);
-               }
-       }
-
-       if (optind > argc - 2) {
-               free(ctx);
-               return command_usage(&aio_read_cmd);
-       }
-
-       ctx->offset = cvtnum(argv[optind]);
-       if (ctx->offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               free(ctx);
-               return 0;
-       }
-       optind++;
-
-       if (ctx->offset & 0x1ff) {
-               printf("offset %" PRId64 " is not sector aligned\n",
-                       ctx->offset);
-               free(ctx);
-               return 0;
-       }
-
-       nr_iov = argc - optind;
-       ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
-
-       gettimeofday(&ctx->t1, NULL);
-       acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
-                             ctx->qiov.size >> 9, aio_read_done, ctx);
-       if (!acb) {
-               free(ctx->buf);
-               free(ctx);
-               return -EIO;
-       }
-
-       return 0;
+    int nr_iov, c;
+    struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+    BlockDriverAIOCB *acb;
+
+    while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+        switch (c) {
+        case 'C':
+            ctx->Cflag = 1;
+            break;
+        case 'P':
+            ctx->Pflag = 1;
+            ctx->pattern = parse_pattern(optarg);
+            if (ctx->pattern < 0) {
+                free(ctx);
+                return 0;
+            }
+            break;
+        case 'q':
+            ctx->qflag = 1;
+            break;
+        case 'v':
+            ctx->vflag = 1;
+            break;
+        default:
+            free(ctx);
+            return command_usage(&aio_read_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        free(ctx);
+        return command_usage(&aio_read_cmd);
+    }
+
+    ctx->offset = cvtnum(argv[optind]);
+    if (ctx->offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        free(ctx);
+        return 0;
+    }
+    optind++;
+
+    if (ctx->offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               ctx->offset);
+        free(ctx);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
+
+    gettimeofday(&ctx->t1, NULL);
+    acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
+                         ctx->qiov.size >> 9, aio_read_done, ctx);
+    if (!acb) {
+        free(ctx->buf);
+        free(ctx);
+        return -EIO;
+    }
+
+    return 0;
 }
 
-static void
-aio_write_help(void)
+static void aio_write_help(void)
 {
-       printf(
+    printf(
 "\n"
-" asynchronously writes a range of bytes from the given offset source \n"
+" asynchronously writes a range of bytes from the given offset source\n"
 " from multiple buffers\n"
 "\n"
 " Example:\n"
@@ -1207,199 +1222,196 @@ aio_write_help(void)
 static int aio_write_f(int argc, char **argv);
 
 static const cmdinfo_t aio_write_cmd = {
-       .name           = "aio_write",
-       .cfunc          = aio_write_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cq] [-P pattern ] off len [len..]",
-       .oneline        = "asynchronously writes a number of bytes",
-       .help           = aio_write_help,
+    .name       = "aio_write",
+    .cfunc      = aio_write_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..]",
+    .oneline    = "asynchronously writes a number of bytes",
+    .help       = aio_write_help,
 };
 
-static int
-aio_write_f(int argc, char **argv)
+static int aio_write_f(int argc, char **argv)
 {
-       int nr_iov, c;
-       int pattern = 0xcd;
-       struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
-       BlockDriverAIOCB *acb;
-
-       while ((c = getopt(argc, argv, "CqP:")) != EOF) {
-               switch (c) {
-               case 'C':
-                       ctx->Cflag = 1;
-                       break;
-               case 'q':
-                       ctx->qflag = 1;
-                       break;
-               case 'P':
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               default:
-                       free(ctx);
-                       return command_usage(&aio_write_cmd);
-               }
-       }
-
-       if (optind > argc - 2) {
-               free(ctx);
-               return command_usage(&aio_write_cmd);
-       }
-
-       ctx->offset = cvtnum(argv[optind]);
-       if (ctx->offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               free(ctx);
-               return 0;
-       }
-       optind++;
-
-       if (ctx->offset & 0x1ff) {
-               printf("offset %" PRId64 " is not sector aligned\n",
-                       ctx->offset);
-               free(ctx);
-               return 0;
-       }
-
-       nr_iov = argc - optind;
-       ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
-
-       gettimeofday(&ctx->t1, NULL);
-       acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
-                             ctx->qiov.size >> 9, aio_write_done, ctx);
-       if (!acb) {
-               free(ctx->buf);
-               free(ctx);
-               return -EIO;
-       }
-
-       return 0;
+    int nr_iov, c;
+    int pattern = 0xcd;
+    struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+    BlockDriverAIOCB *acb;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            ctx->Cflag = 1;
+            break;
+        case 'q':
+            ctx->qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        default:
+            free(ctx);
+            return command_usage(&aio_write_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        free(ctx);
+        return command_usage(&aio_write_cmd);
+    }
+
+    ctx->offset = cvtnum(argv[optind]);
+    if (ctx->offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        free(ctx);
+        return 0;
+    }
+    optind++;
+
+    if (ctx->offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               ctx->offset);
+        free(ctx);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
+
+    gettimeofday(&ctx->t1, NULL);
+    acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
+                          ctx->qiov.size >> 9, aio_write_done, ctx);
+    if (!acb) {
+        free(ctx->buf);
+        free(ctx);
+        return -EIO;
+    }
+
+    return 0;
 }
 
-static int
-aio_flush_f(int argc, char **argv)
+static int aio_flush_f(int argc, char **argv)
 {
-       qemu_aio_flush();
-       return 0;
+    qemu_aio_flush();
+    return 0;
 }
 
 static const cmdinfo_t aio_flush_cmd = {
-       .name           = "aio_flush",
-       .cfunc          = aio_flush_f,
-       .oneline        = "completes all outstanding aio requests"
+    .name       = "aio_flush",
+    .cfunc      = aio_flush_f,
+    .oneline    = "completes all outstanding aio requests"
 };
 
-static int
-flush_f(int argc, char **argv)
+static int flush_f(int argc, char **argv)
 {
-       bdrv_flush(bs);
-       return 0;
+    bdrv_flush(bs);
+    return 0;
 }
 
 static const cmdinfo_t flush_cmd = {
-       .name           = "flush",
-       .altname        = "f",
-       .cfunc          = flush_f,
-       .oneline        = "flush all in-core file state to disk",
+    .name       = "flush",
+    .altname    = "f",
+    .cfunc      = flush_f,
+    .oneline    = "flush all in-core file state to disk",
 };
 
-static int
-truncate_f(int argc, char **argv)
+static int truncate_f(int argc, char **argv)
 {
-       int64_t offset;
-       int ret;
-
-       offset = cvtnum(argv[1]);
-       if (offset < 0) {
-               printf("non-numeric truncate argument -- %s\n", argv[1]);
-               return 0;
-       }
-
-       ret = bdrv_truncate(bs, offset);
-       if (ret < 0) {
-               printf("truncate: %s\n", strerror(-ret));
-               return 0;
-       }
-
-       return 0;
+    int64_t offset;
+    int ret;
+
+    offset = cvtnum(argv[1]);
+    if (offset < 0) {
+        printf("non-numeric truncate argument -- %s\n", argv[1]);
+        return 0;
+    }
+
+    ret = bdrv_truncate(bs, offset);
+    if (ret < 0) {
+        printf("truncate: %s\n", strerror(-ret));
+        return 0;
+    }
+
+    return 0;
 }
 
 static const cmdinfo_t truncate_cmd = {
-       .name           = "truncate",
-       .altname        = "t",
-       .cfunc          = truncate_f,
-       .argmin         = 1,
-       .argmax         = 1,
-       .args           = "off",
-       .oneline        = "truncates the current file at the given offset",
+    .name       = "truncate",
+    .altname    = "t",
+    .cfunc      = truncate_f,
+    .argmin     = 1,
+    .argmax     = 1,
+    .args       = "off",
+    .oneline    = "truncates the current file at the given offset",
 };
 
-static int
-length_f(int argc, char **argv)
+static int length_f(int argc, char **argv)
 {
-        int64_t size;
-       char s1[64];
-
-       size = bdrv_getlength(bs);
-       if (size < 0) {
-               printf("getlength: %s\n", strerror(-size));
-               return 0;
-       }
-
-       cvtstr(size, s1, sizeof(s1));
-       printf("%s\n", s1);
-       return 0;
+    int64_t size;
+    char s1[64];
+
+    size = bdrv_getlength(bs);
+    if (size < 0) {
+        printf("getlength: %s\n", strerror(-size));
+        return 0;
+    }
+
+    cvtstr(size, s1, sizeof(s1));
+    printf("%s\n", s1);
+    return 0;
 }
 
 
 static const cmdinfo_t length_cmd = {
-       .name           = "length",
-       .altname        = "l",
-       .cfunc          = length_f,
-       .oneline        = "gets the length of the current file",
+    .name   = "length",
+    .altname    = "l",
+    .cfunc      = length_f,
+    .oneline    = "gets the length of the current file",
 };
 
 
-static int
-info_f(int argc, char **argv)
+static int info_f(int argc, char **argv)
 {
-       BlockDriverInfo bdi;
-       char s1[64], s2[64];
-       int ret;
+    BlockDriverInfo bdi;
+    char s1[64], s2[64];
+    int ret;
 
-       if (bs->drv && bs->drv->format_name)
-               printf("format name: %s\n", bs->drv->format_name);
-       if (bs->drv && bs->drv->protocol_name)
-               printf("format name: %s\n", bs->drv->protocol_name);
+    if (bs->drv && bs->drv->format_name) {
+        printf("format name: %s\n", bs->drv->format_name);
+    }
+    if (bs->drv && bs->drv->protocol_name) {
+        printf("format name: %s\n", bs->drv->protocol_name);
+    }
 
-       ret = bdrv_get_info(bs, &bdi);
-       if (ret)
-               return 0;
+    ret = bdrv_get_info(bs, &bdi);
+    if (ret) {
+        return 0;
+    }
 
-       cvtstr(bdi.cluster_size, s1, sizeof(s1));
-       cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
+    cvtstr(bdi.cluster_size, s1, sizeof(s1));
+    cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
 
-       printf("cluster size: %s\n", s1);
-       printf("vm state offset: %s\n", s2);
+    printf("cluster size: %s\n", s1);
+    printf("vm state offset: %s\n", s2);
 
-       return 0;
+    return 0;
 }
 
 
 
 static const cmdinfo_t info_cmd = {
-       .name           = "info",
-       .altname        = "i",
-       .cfunc          = info_f,
-       .oneline        = "prints information about the current file",
+    .name       = "info",
+    .altname    = "i",
+    .cfunc      = info_f,
+    .oneline    = "prints information about the current file",
 };
 
-static void
-discard_help(void)
+static void discard_help(void)
 {
-       printf(
+    printf(
 "\n"
 " discards a range of bytes from the given offset\n"
 "\n"
@@ -1415,148 +1427,147 @@ discard_help(void)
 static int discard_f(int argc, char **argv);
 
 static const cmdinfo_t discard_cmd = {
-       .name           = "discard",
-       .altname        = "d",
-       .cfunc          = discard_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cq] off len",
-       .oneline        = "discards a number of bytes at a specified offset",
-       .help           = discard_help,
+    .name       = "discard",
+    .altname    = "d",
+    .cfunc      = discard_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] off len",
+    .oneline    = "discards a number of bytes at a specified offset",
+    .help       = discard_help,
 };
 
-static int
-discard_f(int argc, char **argv)
+static int discard_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, qflag = 0;
-       int c, ret;
-       int64_t offset;
-       int count;
-
-       while ((c = getopt(argc, argv, "Cq")) != EOF) {
-               switch (c) {
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               default:
-                       return command_usage(&discard_cmd);
-               }
-       }
-
-       if (optind != argc - 2) {
-               return command_usage(&discard_cmd);
-       }
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       optind++;
-       count = cvtnum(argv[optind]);
-       if (count < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       gettimeofday(&t1, NULL);
-       ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, count >> BDRV_SECTOR_BITS);
-       gettimeofday(&t2, NULL);
-
-       if (ret < 0) {
-               printf("discard failed: %s\n", strerror(-ret));
-               goto out;
-       }
-
-       /* Finally, report back -- -C gives a parsable format */
-       if (!qflag) {
-               t2 = tsub(t2, t1);
-               print_report("discard", &t2, offset, count, count, 1, Cflag);
-       }
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, ret;
+    int64_t offset;
+    int count;
+
+    while ((c = getopt(argc, argv, "Cq")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        default:
+            return command_usage(&discard_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&discard_cmd);
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    gettimeofday(&t1, NULL);
+    ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
+                       count >> BDRV_SECTOR_BITS);
+    gettimeofday(&t2, NULL);
+
+    if (ret < 0) {
+        printf("discard failed: %s\n", strerror(-ret));
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    if (!qflag) {
+        t2 = tsub(t2, t1);
+        print_report("discard", &t2, offset, count, count, 1, Cflag);
+    }
 
 out:
-       return 0;
+    return 0;
 }
 
-static int
-alloc_f(int argc, char **argv)
+static int alloc_f(int argc, char **argv)
 {
-       int64_t offset;
-       int nb_sectors, remaining;
-       char s1[64];
-       int num, sum_alloc;
-       int ret;
-
-       offset = cvtnum(argv[1]);
-       if (offset & 0x1ff) {
-                printf("offset %" PRId64 " is not sector aligned\n",
-                       offset);
-               return 0;
-       }
-
-       if (argc == 3)
-               nb_sectors = cvtnum(argv[2]);
-       else
-               nb_sectors = 1;
-
-       remaining = nb_sectors;
-       sum_alloc = 0;
-       while (remaining) {
-               ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
-               remaining -= num;
-               if (ret) {
-                       sum_alloc += num;
-               }
-       }
-
-       cvtstr(offset, s1, sizeof(s1));
-
-       printf("%d/%d sectors allocated at offset %s\n",
-              sum_alloc, nb_sectors, s1);
-       return 0;
+    int64_t offset;
+    int nb_sectors, remaining;
+    char s1[64];
+    int num, sum_alloc;
+    int ret;
+
+    offset = cvtnum(argv[1]);
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    if (argc == 3) {
+        nb_sectors = cvtnum(argv[2]);
+    } else {
+        nb_sectors = 1;
+    }
+
+    remaining = nb_sectors;
+    sum_alloc = 0;
+    while (remaining) {
+        ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
+        remaining -= num;
+        if (ret) {
+            sum_alloc += num;
+        }
+    }
+
+    cvtstr(offset, s1, sizeof(s1));
+
+    printf("%d/%d sectors allocated at offset %s\n",
+           sum_alloc, nb_sectors, s1);
+    return 0;
 }
 
 static const cmdinfo_t alloc_cmd = {
-       .name           = "alloc",
-       .altname        = "a",
-       .argmin         = 1,
-       .argmax         = 2,
-       .cfunc          = alloc_f,
-       .args           = "off [sectors]",
-       .oneline        = "checks if a sector is present in the file",
+    .name       = "alloc",
+    .altname    = "a",
+    .argmin     = 1,
+    .argmax     = 2,
+    .cfunc      = alloc_f,
+    .args       = "off [sectors]",
+    .oneline    = "checks if a sector is present in the file",
 };
 
-static int
-map_f(int argc, char **argv)
+static int map_f(int argc, char **argv)
 {
-       int64_t offset;
-       int64_t nb_sectors;
-       char s1[64];
-       int num, num_checked;
-       int ret;
-       const char *retstr;
-
-       offset = 0;
-       nb_sectors = bs->total_sectors;
-
-       do {
-               num_checked = MIN(nb_sectors, INT_MAX);
-               ret = bdrv_is_allocated(bs, offset, num_checked, &num);
-               retstr = ret ? "    allocated" : "not allocated";
-               cvtstr(offset << 9ULL, s1, sizeof(s1));
-               printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n",
-                               offset << 9ULL, num, num_checked, retstr, s1, ret);
-
-               offset += num;
-               nb_sectors -= num;
-       } while(offset < bs->total_sectors);
-
-       return 0;
+    int64_t offset;
+    int64_t nb_sectors;
+    char s1[64];
+    int num, num_checked;
+    int ret;
+    const char *retstr;
+
+    offset = 0;
+    nb_sectors = bs->total_sectors;
+
+    do {
+        num_checked = MIN(nb_sectors, INT_MAX);
+        ret = bdrv_is_allocated(bs, offset, num_checked, &num);
+        retstr = ret ? "    allocated" : "not allocated";
+        cvtstr(offset << 9ULL, s1, sizeof(s1));
+        printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n",
+               offset << 9ULL, num, num_checked, retstr, s1, ret);
+
+        offset += num;
+        nb_sectors -= num;
+    } while (offset < bs->total_sectors);
+
+    return 0;
 }
 
 static const cmdinfo_t map_cmd = {
@@ -1569,50 +1580,48 @@ static const cmdinfo_t map_cmd = {
 };
 
 
-static int
-close_f(int argc, char **argv)
+static int close_f(int argc, char **argv)
 {
-       bdrv_close(bs);
-       bs = NULL;
-       return 0;
+    bdrv_close(bs);
+    bs = NULL;
+    return 0;
 }
 
 static const cmdinfo_t close_cmd = {
-       .name           = "close",
-       .altname        = "c",
-       .cfunc          = close_f,
-       .oneline        = "close the current open file",
+    .name       = "close",
+    .altname    = "c",
+    .cfunc      = close_f,
+    .oneline    = "close the current open file",
 };
 
 static int openfile(char *name, int flags, int growable)
 {
-       if (bs) {
-               fprintf(stderr, "file open already, try 'help close'\n");
-               return 1;
-       }
-
-       if (growable) {
-               if (bdrv_file_open(&bs, name, flags)) {
-                       fprintf(stderr, "%s: can't open device %s\n", progname, name);
-                       return 1;
-               }
-       } else {
-               bs = bdrv_new("hda");
-
-               if (bdrv_open(bs, name, flags, NULL) < 0) {
-                       fprintf(stderr, "%s: can't open device %s\n", progname, name);
-                       bs = NULL;
-                       return 1;
-               }
-       }
-
-       return 0;
+    if (bs) {
+        fprintf(stderr, "file open already, try 'help close'\n");
+        return 1;
+    }
+
+    if (growable) {
+        if (bdrv_file_open(&bs, name, flags)) {
+            fprintf(stderr, "%s: can't open device %s\n", progname, name);
+            return 1;
+        }
+    } else {
+        bs = bdrv_new("hda");
+
+        if (bdrv_open(bs, name, flags, NULL) < 0) {
+            fprintf(stderr, "%s: can't open device %s\n", progname, name);
+            bs = NULL;
+            return 1;
+        }
+    }
+
+    return 0;
 }
 
-static void
-open_help(void)
+static void open_help(void)
 {
-       printf(
+    printf(
 "\n"
 " opens a new file in the requested mode\n"
 "\n"
@@ -1630,80 +1639,78 @@ open_help(void)
 static int open_f(int argc, char **argv);
 
 static const cmdinfo_t open_cmd = {
-       .name           = "open",
-       .altname        = "o",
-       .cfunc          = open_f,
-       .argmin         = 1,
-       .argmax         = -1,
-       .flags          = CMD_NOFILE_OK,
-       .args           = "[-Crsn] [path]",
-       .oneline        = "open the file specified by path",
-       .help           = open_help,
+    .name       = "open",
+    .altname    = "o",
+    .cfunc      = open_f,
+    .argmin     = 1,
+    .argmax     = -1,
+    .flags      = CMD_NOFILE_OK,
+    .args       = "[-Crsn] [path]",
+    .oneline    = "open the file specified by path",
+    .help       = open_help,
 };
 
-static int
-open_f(int argc, char **argv)
+static int open_f(int argc, char **argv)
 {
-       int flags = 0;
-       int readonly = 0;
-       int growable = 0;
-       int c;
-
-       while ((c = getopt(argc, argv, "snrg")) != EOF) {
-               switch (c) {
-               case 's':
-                       flags |= BDRV_O_SNAPSHOT;
-                       break;
-               case 'n':
-                       flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
-                       break;
-               case 'r':
-                       readonly = 1;
-                       break;
-               case 'g':
-                       growable = 1;
-                       break;
-               default:
-                       return command_usage(&open_cmd);
-               }
-       }
-
-       if (!readonly) {
-            flags |= BDRV_O_RDWR;
+    int flags = 0;
+    int readonly = 0;
+    int growable = 0;
+    int c;
+
+    while ((c = getopt(argc, argv, "snrg")) != EOF) {
+        switch (c) {
+        case 's':
+            flags |= BDRV_O_SNAPSHOT;
+            break;
+        case 'n':
+            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+            break;
+        case 'r':
+            readonly = 1;
+            break;
+        case 'g':
+            growable = 1;
+            break;
+        default:
+            return command_usage(&open_cmd);
         }
+    }
+
+    if (!readonly) {
+        flags |= BDRV_O_RDWR;
+    }
 
-       if (optind != argc - 1)
-               return command_usage(&open_cmd);
+    if (optind != argc - 1) {
+        return command_usage(&open_cmd);
+    }
 
-       return openfile(argv[optind], flags, growable);
+    return openfile(argv[optind], flags, growable);
 }
 
-static int
-init_args_command(
-        int     index)
+static int init_args_command(int index)
 {
-       /* only one device allowed so far */
-       if (index >= 1)
-               return 0;
-       return ++index;
+    /* only one device allowed so far */
+    if (index >= 1) {
+        return 0;
+    }
+    return ++index;
 }
 
-static int
-init_check_command(
-       const cmdinfo_t *ct)
+static int init_check_command(const cmdinfo_t *ct)
 {
-       if (ct->flags & CMD_FLAG_GLOBAL)
-               return 1;
-       if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
-               fprintf(stderr, "no file open, try 'help open'\n");
-               return 0;
-       }
-       return 1;
+    if (ct->flags & CMD_FLAG_GLOBAL) {
+        return 1;
+    }
+    if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+        fprintf(stderr, "no file open, try 'help open'\n");
+        return 0;
+    }
+    return 1;
 }
 
 static void usage(const char *name)
 {
-       printf(
+    printf(
 "Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
 "QEMU Disk exerciser\n"
 "\n"
@@ -1717,115 +1724,117 @@ static void usage(const char *name)
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
 "\n",
-       name);
+    name);
 }
 
 
 int main(int argc, char **argv)
 {
-       int readonly = 0;
-       int growable = 0;
-       const char *sopt = "hVc:rsnmgk";
-        const struct option lopt[] = {
-               { "help", 0, NULL, 'h' },
-               { "version", 0, NULL, 'V' },
-               { "offset", 1, NULL, 'o' },
-               { "cmd", 1, NULL, 'c' },
-               { "read-only", 0, NULL, 'r' },
-               { "snapshot", 0, NULL, 's' },
-               { "nocache", 0, NULL, 'n' },
-               { "misalign", 0, NULL, 'm' },
-               { "growable", 0, NULL, 'g' },
-               { "native-aio", 0, NULL, 'k' },
-               { NULL, 0, NULL, 0 }
-       };
-       int c;
-       int opt_index = 0;
-       int flags = 0;
-
-       progname = basename(argv[0]);
-
-       while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
-               switch (c) {
-               case 's':
-                       flags |= BDRV_O_SNAPSHOT;
-                       break;
-               case 'n':
-                       flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
-                       break;
-               case 'c':
-                       add_user_command(optarg);
-                       break;
-               case 'r':
-                       readonly = 1;
-                       break;
-               case 'm':
-                       misalign = 1;
-                       break;
-               case 'g':
-                       growable = 1;
-                       break;
-               case 'k':
-                       flags |= BDRV_O_NATIVE_AIO;
-                       break;
-               case 'V':
-                       printf("%s version %s\n", progname, VERSION);
-                       exit(0);
-               case 'h':
-                       usage(progname);
-                       exit(0);
-               default:
-                       usage(progname);
-                       exit(1);
-               }
-       }
-
-       if ((argc - optind) > 1) {
-               usage(progname);
-               exit(1);
-       }
-
-       bdrv_init();
-
-       /* initialize commands */
-       quit_init();
-       help_init();
-       add_command(&open_cmd);
-       add_command(&close_cmd);
-       add_command(&read_cmd);
-       add_command(&readv_cmd);
-       add_command(&write_cmd);
-       add_command(&writev_cmd);
-       add_command(&multiwrite_cmd);
-       add_command(&aio_read_cmd);
-       add_command(&aio_write_cmd);
-       add_command(&aio_flush_cmd);
-       add_command(&flush_cmd);
-       add_command(&truncate_cmd);
-       add_command(&length_cmd);
-       add_command(&info_cmd);
-       add_command(&discard_cmd);
-       add_command(&alloc_cmd);
-       add_command(&map_cmd);
-
-       add_args_command(init_args_command);
-       add_check_command(init_check_command);
-
-       /* open the device */
-       if (!readonly) {
-            flags |= BDRV_O_RDWR;
+    int readonly = 0;
+    int growable = 0;
+    const char *sopt = "hVc:rsnmgk";
+    const struct option lopt[] = {
+        { "help", 0, NULL, 'h' },
+        { "version", 0, NULL, 'V' },
+        { "offset", 1, NULL, 'o' },
+        { "cmd", 1, NULL, 'c' },
+        { "read-only", 0, NULL, 'r' },
+        { "snapshot", 0, NULL, 's' },
+        { "nocache", 0, NULL, 'n' },
+        { "misalign", 0, NULL, 'm' },
+        { "growable", 0, NULL, 'g' },
+        { "native-aio", 0, NULL, 'k' },
+        { NULL, 0, NULL, 0 }
+    };
+    int c;
+    int opt_index = 0;
+    int flags = 0;
+
+    progname = basename(argv[0]);
+
+    while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
+        switch (c) {
+        case 's':
+            flags |= BDRV_O_SNAPSHOT;
+            break;
+        case 'n':
+            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+            break;
+        case 'c':
+            add_user_command(optarg);
+            break;
+        case 'r':
+            readonly = 1;
+            break;
+        case 'm':
+            misalign = 1;
+            break;
+        case 'g':
+            growable = 1;
+            break;
+        case 'k':
+            flags |= BDRV_O_NATIVE_AIO;
+            break;
+        case 'V':
+            printf("%s version %s\n", progname, VERSION);
+            exit(0);
+        case 'h':
+            usage(progname);
+            exit(0);
+        default:
+            usage(progname);
+            exit(1);
         }
+    }
+
+    if ((argc - optind) > 1) {
+        usage(progname);
+        exit(1);
+    }
 
-       if ((argc - optind) == 1)
-               openfile(argv[optind], flags, growable);
-       command_loop();
+    bdrv_init();
+
+    /* initialize commands */
+    quit_init();
+    help_init();
+    add_command(&open_cmd);
+    add_command(&close_cmd);
+    add_command(&read_cmd);
+    add_command(&readv_cmd);
+    add_command(&write_cmd);
+    add_command(&writev_cmd);
+    add_command(&multiwrite_cmd);
+    add_command(&aio_read_cmd);
+    add_command(&aio_write_cmd);
+    add_command(&aio_flush_cmd);
+    add_command(&flush_cmd);
+    add_command(&truncate_cmd);
+    add_command(&length_cmd);
+    add_command(&info_cmd);
+    add_command(&discard_cmd);
+    add_command(&alloc_cmd);
+    add_command(&map_cmd);
+
+    add_args_command(init_args_command);
+    add_check_command(init_check_command);
+
+    /* open the device */
+    if (!readonly) {
+        flags |= BDRV_O_RDWR;
+    }
+
+    if ((argc - optind) == 1) {
+        openfile(argv[optind], flags, growable);
+    }
+    command_loop();
 
-       /*
-        * Make sure all outstanding requests get flushed the program exits.
-        */
-       qemu_aio_flush();
+    /*
+     * Make sure all outstanding requests get flushed the program exits.
+     */
+    qemu_aio_flush();
 
-       if (bs)
-               bdrv_close(bs);
-       return 0;
+    if (bs) {
+        bdrv_close(bs);
+    }
+    return 0;
 }
index e6d7adc3af7c797ae14ec3d967da60d50e00ada8..64114dd4488d4de5bb2e71f81b9b989891b731d2 100644 (file)
@@ -160,6 +160,14 @@ an untrusted format header.
 This option specifies the serial number to assign to the device.
 @item addr=@var{addr}
 Specify the controller's PCI address (if=virtio only).
+@item werror=@var{action},rerror=@var{action}
+Specify which @var{action} to take on write and read errors. Valid actions are:
+"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
+"report" (report the error to the guest), "enospc" (pause QEMU only if the
+host disk is full; report the error to the guest otherwise).
+The default setting is @option{werror=enospc} and @option{rerror=report}.
+@item readonly
+Open drive @option{file} as read-only. Guest write attempts will fail.
 @end table
 
 By default, writethrough caching is used for all block device.  This means that