Skip to contentSkip to conversation

Block patches

GIT PULL New Kevin Wolf 2 participants 20 messages Apr 30, 2010 – May 3, 2010

Subsystems (2)
lore
Share & tools
lore

Kevin Wolf

author
#0 lore raw

Hi Anthony,

this is the second part of the block patches in my queue that I promised in the pull request last week. I also included the high watermark patch even if it didn't sit on the list for a very long time - but the people that I expected to comment on it have already done so, either on the list or internally.

Kevin

The following changes since commit 9ed7b059ef776a3921cfd085e891f45076922542:
Amit Shah (1):
virtio-serial: Implement flow control for individual ports

are available in the git repository at:

git://repo.or.cz/qemu/kevin.git for-anthony

Christoph Hellwig (1):
block: separate raw images from the file protocol

Jan Kiszka (1):
block: Release allocated options after bdrv_open

Kevin Wolf (10):
block: Split bdrv_open
block: Avoid forward declaration of bdrv_open_common
block: Open the underlying image file in generic code
block: bdrv_has_zero_init
vmdk: Fix COW
vmdk: Clean up backing file handling
vmdk: Convert to bdrv_open
qcow2: Remove abort on free_clusters failure
block: Add wr_highest_sector blockstat qemu-img rebase: Fix output image corruption

Stefan Hajnoczi (6):
block: Set backing_hd to NULL after deleting it
qcow2: Avoid shadowing variable in alloc_clusters_noref()
raw-posix: Use pread/pwrite instead of lseek+read/write
block: Cache total_sectors to reduce bdrv_getlength calls
qemu-img: Add 'resize' command to grow/shrink disk images
qcow2: Implement bdrv_truncate() for growing images

 Makefile.objs          |    2 +-
 block.c                |  384 ++++++++++++++++++++++++++++++++++--------------
 block.h                |    2 +
 block/blkdebug.c       |   17 +--
 block/bochs.c          |    2 +-
 block/cloop.c          |    2 +-
 block/cow.c            |    2 +-
 block/curl.c           |   10 +-
 block/dmg.c            |    2 +-
 block/nbd.c            |    2 +-
 block/parallels.c      |    2 +-
 block/qcow.c           |   67 ++++-----
 block/qcow2-cluster.c  |   64 ++++----
 block/qcow2-refcount.c |   86 ++++++------
 block/qcow2-snapshot.c |   22 ++--
 block/qcow2.c          |  110 +++++++++-----
 block/qcow2.h          |    8 +-
 block/raw-posix.c      |   62 +++------
 block/raw-win32.c      |   16 +-
 block/raw.c            |  144 ++++++++++++++++++
 block/vdi.c            |   29 +---
 block/vmdk.c           |  140 +++++-------------
 block/vpc.c            |   32 ++---
 block/vvfat.c          |    2 +-
 block_int.h            |    6 +-
 qemu-img-cmds.hx       |    6 +
 qemu-img.c             |  104 +++++++++++++-
 qemu-img.texi          |   12 ++
 28 files changed, 843 insertions(+), 494 deletions(-)
 create mode 100644 block/raw.c
author
#1 lore raw

PATCH 1/18 block: separate raw images from the file protocol

From: Christoph Hellwig <[email protected]>

We're running into various problems because the "raw" file access, which is used internally by the various image formats is entangled with the "raw" image format, which maps the VM view 1:1 to a file system.

This patch renames the raw file backends to the file protocol which is treated like other protocols (e.g. nbd and http) and adds a new "raw" image format which is just a wrapper around calls to the underlying protocol.

The patch is surprisingly simple, besides changing the probing logical in block.c to only look for image formats when using bdrv_open and renaming of the old raw protocols to file there's almost nothing in there.

For creating images, a new bdrv_create_file is introduced which guesses the protocol to use. This allows using qemu-img create -f raw (or just using the default) for both files and host devices. Converting the other format drivers to use this function to create their images is left for later patches.

The only issues still open are in the handling of the host devices. Firstly in current qemu we can specifiy the host* format names on various command line acceping images, but the new code can't do that without adding some translation. Second the layering breaks the no_zero_init flag in the BlockDriver used by qemu-img. I'm not happy how this is done per-driver instead of per-state so I'll prepare a separate patch to clean this up.

There's some more cleanup opportunity after this patch, e.g. using separate lists and registration functions for image formats vs protocols and maybe even host drivers, but this can be done at a later stage.

Also there's a check for protocol in bdrv_open for the BDRV_O_SNAPSHOT case that I don't quite understand, but which I fear won't work as expected - possibly even before this patch.

Note that this patch requires various recent block patches from Kevin and me, which should all be in his block queue.

---
 Makefile.objs     |    2 +-
 block.c           |   74 ++++++++++++++---------
 block.h           |    1 +
 block/raw-posix.c |   15 +++--
 block/raw-win32.c |   12 ++--
 block/raw.c       |  171 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 235 insertions(+), 40 deletions(-)
 create mode 100644 block/raw.c
Makefile.objs +1 -1
index 1c7c64b..4f65bfb 100644
@@ -12,7 +12,7 @@ block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
-block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
+block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
 block-nested-y += parallels.o nbd.o blkdebug.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
block.c +45 -29

118 lines not on this page · raw message

block.h +1 -0
index 05ad572..f58edf1 100644
@@ -57,6 +57,7 @@ BlockDriver *bdrv_find_format(const char *format_name);
 BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
 int bdrv_create(BlockDriver *drv, const char* filename,
     QEMUOptionParameter *options);
+int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
 BlockDriverState *bdrv_new(const char *device_name);
 void bdrv_delete(BlockDriverState *bs);
 int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
block/raw-posix.c +10 -5
index 4cda9c1..8f57ab0 100644
@@ -768,8 +768,9 @@ static QEMUOptionParameter raw_create_options[] = {
     { NULL }
 };
 
-static BlockDriver bdrv_raw = {
-    .format_name = "raw",
+static BlockDriver bdrv_file = {
+    .format_name = "file",
+    .protocol_name = "file",
     .instance_size = sizeof(BDRVRawState),
     .bdrv_probe = NULL, /* no probe for protocols */
     .bdrv_open = raw_open,
@@ -1026,6 +1027,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
 
 static BlockDriver bdrv_host_device = {
     .format_name        = "host_device",
+    .protocol_name        = "host_device",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device  = hdev_probe_device,
     .bdrv_open          = hdev_open,
@@ -1140,6 +1142,7 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag)
 
 static BlockDriver bdrv_host_floppy = {
     .format_name        = "host_floppy",
+    .protocol_name      = "host_floppy",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device	= floppy_probe_device,
     .bdrv_open          = floppy_open,
@@ -1239,6 +1242,7 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
 
 static BlockDriver bdrv_host_cdrom = {
     .format_name        = "host_cdrom",
+    .protocol_name      = "host_cdrom",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device	= cdrom_probe_device,
     .bdrv_open          = cdrom_open,
@@ -1361,6 +1365,7 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
 
 static BlockDriver bdrv_host_cdrom = {
     .format_name        = "host_cdrom",
+    .protocol_name      = "host_cdrom",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device	= cdrom_probe_device,
     .bdrv_open          = cdrom_open,
@@ -1385,13 +1390,13 @@ static BlockDriver bdrv_host_cdrom = {
 };
 #endif /* __FreeBSD__ */
 
-static void bdrv_raw_init(void)
+static void bdrv_file_init(void)
 {
     /*
      * Register all the drivers.  Note that order is important, the driver
      * registered last will get probed first.
      */
-    bdrv_register(&bdrv_raw);
+    bdrv_register(&bdrv_file);
     bdrv_register(&bdrv_host_device);
 #ifdef __linux__
     bdrv_register(&bdrv_host_floppy);
@@ -1402,4 +1407,4 @@ static void bdrv_raw_init(void)
 #endif
 }
 
-block_init(bdrv_raw_init);
+block_init(bdrv_file_init);
block/raw-win32.c +7 -5
index 526764f..eadebeb 100644
@@ -238,8 +238,9 @@ static QEMUOptionParameter raw_create_options[] = {
     { NULL }
 };
 
-static BlockDriver bdrv_raw = {
-    .format_name	= "raw",
+static BlockDriver bdrv_file = {
+    .format_name	= "file",
+    .protocol_name	= "file",
     .instance_size	= sizeof(BDRVRawState),
     .bdrv_open		= raw_open,
     .bdrv_close		= raw_close,
@@ -395,6 +396,7 @@ static int raw_set_locked(BlockDriverState *bs, int locked)
 
 static BlockDriver bdrv_host_device = {
     .format_name	= "host_device",
+    .protocol_name	= "host_device",
     .instance_size	= sizeof(BDRVRawState),
     .bdrv_probe_device	= hdev_probe_device,
     .bdrv_open		= hdev_open,
@@ -406,10 +408,10 @@ static BlockDriver bdrv_host_device = {
     .bdrv_getlength	= raw_getlength,
 };
 
-static void bdrv_raw_init(void)
+static void bdrv_file_init(void)
 {
-    bdrv_register(&bdrv_raw);
+    bdrv_register(&bdrv_file);
     bdrv_register(&bdrv_host_device);
 }
 
-block_init(bdrv_raw_init);
+block_init(bdrv_file_init);
block/raw.c new file +171 -0

171 lines not on this page · raw message

Signature · 1 line
1.6.6.1
author
#2 lore raw

PATCH 2/18 block: Split bdrv_open

In reply to Kevin Wolf

bdrv_open contains quite some code that is only useful for opening images (as opposed to opening files by a protocol), for example snapshots.

This patch splits the code so that we have bdrv_open_file() for files (uses protocols), bdrv_open() for images (uses format drivers) and bdrv_open_common() for the code common for opening both images and files.

---
 block.c |  135 ++++++++++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 86 insertions(+), 49 deletions(-)
block.c +86 -49
index ad681db..6efc2b3 100644
@@ -42,6 +42,9 @@
 #include <windows.h>
 #endif
 
+static int bdrv_open_common(BlockDriverState *bs, const char *filename,
+    int flags, BlockDriver *drv);
+
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
@@ -350,6 +353,9 @@ static BlockDriver *find_image_format(const char *filename)
     return drv;
 }
 
+/*
+ * Opens a file using a protocol (file, host_device, nbd, ...)
+ */
 int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
 {
     BlockDriverState *bs;
@@ -362,7 +368,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
     }
 
     bs = bdrv_new("");
-    ret = bdrv_open(bs, filename, flags, drv);
+    ret = bdrv_open_common(bs, filename, flags, drv);
     if (ret < 0) {
         bdrv_delete(bs);
         return ret;
@@ -372,19 +378,13 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
     return 0;
 }
 
+/*
+ * Opens a disk image (raw, qcow2, vmdk, ...)
+ */
 int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
               BlockDriver *drv)
 {
-    int ret, open_flags;
-    char tmp_filename[PATH_MAX];
-    char backing_filename[PATH_MAX];
-
-    bs->is_temporary = 0;
-    bs->encrypted = 0;
-    bs->valid_key = 0;
-    bs->open_flags = flags;
-    /* buffer_alignment defaulted to 512, drivers can change this value */
-    bs->buffer_alignment = 512;
+    int ret;
 
     if (flags & BDRV_O_SNAPSHOT) {
         BlockDriverState *bs1;
@@ -392,6 +392,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         int is_protocol = 0;
         BlockDriver *bdrv_qcow2;
         QEMUOptionParameter *options;
+        char tmp_filename[PATH_MAX];
+        char backing_filename[PATH_MAX];
 
         /* if snapshot, we create a temporary backing file and open it
            instead of opening 'filename' directly */
@@ -439,8 +441,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         bs->is_temporary = 1;
     }
 
-    pstrcpy(bs->filename, sizeof(bs->filename), filename);
-
+    /* Find the right image format driver */
     if (!drv) {
         drv = find_image_format(filename);
     }
@@ -449,11 +450,81 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         ret = -ENOENT;
         goto unlink_and_fail;
     }
-    if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
-        ret = -ENOTSUP;
+
+    /* Open the image */
+    ret = bdrv_open_common(bs, filename, flags, drv);
+    if (ret < 0) {
         goto unlink_and_fail;
     }
 
+    /* If there is a backing file, use it */
+    if ((flags & BDRV_O_NO_BACKING) == 0 && bs->backing_file[0] != '\0') {
+        char backing_filename[PATH_MAX];
+        int back_flags;
+        BlockDriver *back_drv = NULL;
+
+        bs->backing_hd = bdrv_new("");
+        path_combine(backing_filename, sizeof(backing_filename),
+                     filename, bs->backing_file);
+        if (bs->backing_format[0] != '\0')
+            back_drv = bdrv_find_format(bs->backing_format);
+
+        /* backing files always opened read-only */
+        back_flags =
+            flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
+
+        ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv);
+        if (ret < 0) {
+            bdrv_close(bs);
+            return ret;
+        }
+        if (bs->is_temporary) {
+            bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
+        } else {
+            /* base image inherits from "parent" */
+            bs->backing_hd->keep_read_only = bs->keep_read_only;
+        }
+    }
+
+    if (!bdrv_key_required(bs)) {
+        /* call the change callback */
+        bs->media_changed = 1;
+        if (bs->change_cb)
+            bs->change_cb(bs->change_opaque);
+    }
+
+    return 0;
+
+unlink_and_fail:
+    if (bs->is_temporary) {
+        unlink(filename);
+    }
+    return ret;
+}
+
+/*
+ * Common part for opening disk images and files
+ */
+static int bdrv_open_common(BlockDriverState *bs, const char *filename,
+    int flags, BlockDriver *drv)
+{
+    int ret, open_flags;
+
+    assert(drv != NULL);
+
+    bs->is_temporary = 0;
+    bs->encrypted = 0;
+    bs->valid_key = 0;
+    bs->open_flags = flags;
+    /* buffer_alignment defaulted to 512, drivers can change this value */
+    bs->buffer_alignment = 512;
+
+    pstrcpy(bs->filename, sizeof(bs->filename), filename);
+
+    if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
+        return -ENOTSUP;
+    }
+
     bs->drv = drv;
     bs->opaque = qemu_mallocz(drv->instance_size);
 
@@ -493,46 +564,12 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         unlink(filename);
     }
 #endif
-    if ((flags & BDRV_O_NO_BACKING) == 0 && bs->backing_file[0] != '\0') {
-        /* if there is a backing file, use it */
-        BlockDriver *back_drv = NULL;
-        bs->backing_hd = bdrv_new("");
-        path_combine(backing_filename, sizeof(backing_filename),
-                     filename, bs->backing_file);
-        if (bs->backing_format[0] != '\0')
-            back_drv = bdrv_find_format(bs->backing_format);
-
-        /* backing files always opened read-only */
-        open_flags &= ~BDRV_O_RDWR;
-
-        ret = bdrv_open(bs->backing_hd, backing_filename, open_flags, back_drv);
-        if (ret < 0) {
-            bdrv_close(bs);
-            return ret;
-        }
-        if (bs->is_temporary) {
-            bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
-        } else {
-            /* base image inherits from "parent" */
-            bs->backing_hd->keep_read_only = bs->keep_read_only;
-        }
-    }
-
-    if (!bdrv_key_required(bs)) {
-        /* call the change callback */
-        bs->media_changed = 1;
-        if (bs->change_cb)
-            bs->change_cb(bs->change_opaque);
-    }
     return 0;
 
 free_and_fail:
     qemu_free(bs->opaque);
     bs->opaque = NULL;
     bs->drv = NULL;
-unlink_and_fail:
-    if (bs->is_temporary)
-        unlink(filename);
     return ret;
 }
 
Signature · 1 line
1.6.6.1
author
#3 lore raw

PATCH 3/18 block: Avoid forward declaration of bdrv_open_common

In reply to Kevin Wolf

Move bdrv_open_common so it's defined before its callers and remove the forward declaration.

---
 block.c |  145 +++++++++++++++++++++++++++++++--------------------------------
 1 files changed, 71 insertions(+), 74 deletions(-)
block.c +71 -74
index 6efc2b3..f9b5e53 100644
@@ -42,9 +42,6 @@
 #include <windows.h>
 #endif
 
-static int bdrv_open_common(BlockDriverState *bs, const char *filename,
-    int flags, BlockDriver *drv);
-
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
@@ -354,6 +351,77 @@ static BlockDriver *find_image_format(const char *filename)
 }
 
 /*
+ * Common part for opening disk images and files
+ */
+static int bdrv_open_common(BlockDriverState *bs, const char *filename,
+    int flags, BlockDriver *drv)
+{
+    int ret, open_flags;
+
+    assert(drv != NULL);
+
+    bs->is_temporary = 0;
+    bs->encrypted = 0;
+    bs->valid_key = 0;
+    bs->open_flags = flags;
+    /* buffer_alignment defaulted to 512, drivers can change this value */
+    bs->buffer_alignment = 512;
+
+    pstrcpy(bs->filename, sizeof(bs->filename), filename);
+
+    if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
+        return -ENOTSUP;
+    }
+
+    bs->drv = drv;
+    bs->opaque = qemu_mallocz(drv->instance_size);
+
+    /*
+     * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
+     * write cache to the guest.  We do need the fdatasync to flush
+     * out transactions for block allocations, and we maybe have a
+     * volatile write cache in our backing device to deal with.
+     */
+    if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
+        bs->enable_write_cache = 1;
+
+    /*
+     * Clear flags that are internal to the block layer before opening the
+     * image.
+     */
+    open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
+
+    /*
+     * Snapshots should be writeable.
+     */
+    if (bs->is_temporary) {
+        open_flags |= BDRV_O_RDWR;
+    }
+
+    ret = drv->bdrv_open(bs, filename, open_flags);
+    if (ret < 0) {
+        goto free_and_fail;
+    }
+
+    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
+    if (drv->bdrv_getlength) {
+        bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+    }
+#ifndef _WIN32
+    if (bs->is_temporary) {
+        unlink(filename);
+    }
+#endif
+    return 0;
+
+free_and_fail:
+    qemu_free(bs->opaque);
+    bs->opaque = NULL;
+    bs->drv = NULL;
+    return ret;
+}
+
+/*
  * Opens a file using a protocol (file, host_device, nbd, ...)
  */
 int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
@@ -502,77 +570,6 @@ unlink_and_fail:
     return ret;
 }
 
-/*
- * Common part for opening disk images and files
- */
-static int bdrv_open_common(BlockDriverState *bs, const char *filename,
-    int flags, BlockDriver *drv)
-{
-    int ret, open_flags;
-
-    assert(drv != NULL);
-
-    bs->is_temporary = 0;
-    bs->encrypted = 0;
-    bs->valid_key = 0;
-    bs->open_flags = flags;
-    /* buffer_alignment defaulted to 512, drivers can change this value */
-    bs->buffer_alignment = 512;
-
-    pstrcpy(bs->filename, sizeof(bs->filename), filename);
-
-    if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
-        return -ENOTSUP;
-    }
-
-    bs->drv = drv;
-    bs->opaque = qemu_mallocz(drv->instance_size);
-
-    /*
-     * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
-     * write cache to the guest.  We do need the fdatasync to flush
-     * out transactions for block allocations, and we maybe have a
-     * volatile write cache in our backing device to deal with.
-     */
-    if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
-        bs->enable_write_cache = 1;
-
-    /*
-     * Clear flags that are internal to the block layer before opening the
-     * image.
-     */
-    open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
-
-    /*
-     * Snapshots should be writeable.
-     */
-    if (bs->is_temporary) {
-        open_flags |= BDRV_O_RDWR;
-    }
-
-    ret = drv->bdrv_open(bs, filename, open_flags);
-    if (ret < 0) {
-        goto free_and_fail;
-    }
-
-    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
-    if (drv->bdrv_getlength) {
-        bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
-    }
-#ifndef _WIN32
-    if (bs->is_temporary) {
-        unlink(filename);
-    }
-#endif
-    return 0;
-
-free_and_fail:
-    qemu_free(bs->opaque);
-    bs->opaque = NULL;
-    bs->drv = NULL;
-    return ret;
-}
-
 void bdrv_close(BlockDriverState *bs)
 {
     if (bs->drv) {
Signature · 1 line
1.6.6.1
author
#4 lore raw

PATCH 4/18 block: Open the underlying image file in generic code

In reply to Kevin Wolf

Format drivers shouldn't need to bother with things like file names, but rather just get an open BlockDriverState for the underlying protocol. This patch introduces this behaviour for bdrv_open implementation. For protocols which need to access the filename to open their file/device/connection/... a new callback bdrv_file_open is introduced which doesn't get an underlying file opened.

For now, also some of the more obscure formats use bdrv_file_open because they open() the file themselves instead of using the block.c functions. They need to be fixed in later patches.

---
 block.c                |   26 +++++++++++++++-
 block/blkdebug.c       |   17 +++------
 block/bochs.c          |    2 +-
 block/cloop.c          |    2 +-
 block/cow.c            |    2 +-
 block/curl.c           |   10 +++---
 block/dmg.c            |    2 +-
 block/nbd.c            |    2 +-
 block/parallels.c      |    2 +-
 block/qcow.c           |   67 ++++++++++++++++++----------------------
 block/qcow2-cluster.c  |   64 ++++++++++++++++++++------------------
 block/qcow2-refcount.c |   80 ++++++++++++++++++++++++------------------------
 block/qcow2-snapshot.c |   22 ++++++------
 block/qcow2.c          |   66 +++++++++++++++++-----------------------
 block/qcow2.h          |    2 +-
 block/raw-posix.c      |   10 +++---
 block/raw-win32.c      |    4 +-
 block/raw.c            |   63 +++++++++++---------------------------
 block/vdi.c            |   29 +++++------------
 block/vmdk.c           |    2 +-
 block/vpc.c            |   32 +++++++------------
 block/vvfat.c          |    2 +-
 block_int.h            |    5 ++-
 23 files changed, 237 insertions(+), 276 deletions(-)
block.c +25 -1
index f9b5e53..eb1d562 100644
@@ -288,6 +288,8 @@ static BlockDriver *find_protocol(const char *filename)
     int len;
     const char *p;
 
+    /* TODO Drivers without bdrv_file_open must be specified explicitly */
+
 #ifdef _WIN32
     if (is_windows_drive(filename) ||
         is_windows_drive_prefix(filename))
@@ -360,6 +362,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
 
     assert(drv != NULL);
 
+    bs->file = NULL;
     bs->is_temporary = 0;
     bs->encrypted = 0;
     bs->valid_key = 0;
@@ -398,7 +401,16 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
         open_flags |= BDRV_O_RDWR;
     }
 
-    ret = drv->bdrv_open(bs, filename, open_flags);
+    /* Open the image, either directly or using a protocol */
+    if (drv->bdrv_file_open) {
+        ret = drv->bdrv_file_open(bs, filename, open_flags);
+    } else {
+        ret = bdrv_file_open(&bs->file, filename, open_flags);
+        if (ret >= 0) {
+            ret = drv->bdrv_open(bs, open_flags);
+        }
+    }
+
     if (ret < 0) {
         goto free_and_fail;
     }
@@ -415,6 +427,10 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
     return 0;
 
 free_and_fail:
+    if (bs->file) {
+        bdrv_delete(bs->file);
+        bs->file = NULL;
+    }
     qemu_free(bs->opaque);
     bs->opaque = NULL;
     bs->drv = NULL;
@@ -585,6 +601,10 @@ void bdrv_close(BlockDriverState *bs)
         bs->opaque = NULL;
         bs->drv = NULL;
 
+        if (bs->file != NULL) {
+            bdrv_close(bs->file);
+        }
+
         /* call the change callback */
         bs->media_changed = 1;
         if (bs->change_cb)
@@ -600,6 +620,10 @@ void bdrv_delete(BlockDriverState *bs)
     }
 
     bdrv_close(bs);
+    if (bs->file != NULL) {
+        bdrv_delete(bs->file);
+    }
+
     qemu_free(bs);
 }
 
block/blkdebug.c +6 -11
index 643c397..bb4a91a 100644
@@ -44,7 +44,6 @@ typedef struct BlkdebugVars {
 } BlkdebugVars;
 
 typedef struct BDRVBlkdebugState {
-    BlockDriverState *hd;
     BlkdebugVars vars;
     QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
 } BDRVBlkdebugState;
@@ -303,7 +302,7 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
     filename = c + 1;
 
     /* Open the backing file */
-    ret = bdrv_file_open(&s->hd, filename, flags);
+    ret = bdrv_file_open(&bs->file, filename, flags);
     if (ret < 0) {
         return ret;
     }
@@ -362,7 +361,7 @@ static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
     }
 
     BlockDriverAIOCB *acb =
-        bdrv_aio_readv(s->hd, sector_num, qiov, nb_sectors, cb, opaque);
+        bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
     return acb;
 }
 
@@ -377,7 +376,7 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
     }
 
     BlockDriverAIOCB *acb =
-        bdrv_aio_writev(s->hd, sector_num, qiov, nb_sectors, cb, opaque);
+        bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
     return acb;
 }
 
@@ -393,21 +392,17 @@ static void blkdebug_close(BlockDriverState *bs)
             qemu_free(rule);
         }
     }
-
-    bdrv_delete(s->hd);
 }
 
 static void blkdebug_flush(BlockDriverState *bs)
 {
-    BDRVBlkdebugState *s = bs->opaque;
-    bdrv_flush(s->hd);
+    bdrv_flush(bs->file);
 }
 
 static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
     BlockDriverCompletionFunc *cb, void *opaque)
 {
-    BDRVBlkdebugState *s = bs->opaque;
-    return bdrv_aio_flush(s->hd, cb, opaque);
+    return bdrv_aio_flush(bs->file, cb, opaque);
 }
 
 static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
@@ -456,7 +451,7 @@ static BlockDriver bdrv_blkdebug = {
 
     .instance_size      = sizeof(BDRVBlkdebugState),
 
-    .bdrv_open          = blkdebug_open,
+    .bdrv_file_open     = blkdebug_open,
     .bdrv_close         = blkdebug_close,
     .bdrv_flush         = blkdebug_flush,
 
block/bochs.c +1 -1
index fb83594..e952670 100644
@@ -252,7 +252,7 @@ static BlockDriver bdrv_bochs = {
     .format_name	= "bochs",
     .instance_size	= sizeof(BDRVBochsState),
     .bdrv_probe		= bochs_probe,
-    .bdrv_open		= bochs_open,
+    .bdrv_file_open	= bochs_open,
     .bdrv_read		= bochs_read,
     .bdrv_close		= bochs_close,
 };
block/cloop.c +1 -1
index 06c687e..e4f995b 100644
@@ -158,7 +158,7 @@ static BlockDriver bdrv_cloop = {
     .format_name	= "cloop",
     .instance_size	= sizeof(BDRVCloopState),
     .bdrv_probe		= cloop_probe,
-    .bdrv_open		= cloop_open,
+    .bdrv_file_open	= cloop_open,
     .bdrv_read		= cloop_read,
     .bdrv_close		= cloop_close,
 };
block/cow.c +1 -1
index 97e9745..fde066e 100644
@@ -291,7 +291,7 @@ static BlockDriver bdrv_cow = {
     .format_name	= "cow",
     .instance_size	= sizeof(BDRVCowState),
     .bdrv_probe		= cow_probe,
-    .bdrv_open		= cow_open,
+    .bdrv_file_open	= cow_open,
     .bdrv_read		= cow_read,
     .bdrv_write		= cow_write,
     .bdrv_close		= cow_close,
block/curl.c +5 -5
index 2cf72cb..b944740 100644
@@ -495,7 +495,7 @@ static BlockDriver bdrv_http = {
     .protocol_name   = "http",
 
     .instance_size   = sizeof(BDRVCURLState),
-    .bdrv_open       = curl_open,
+    .bdrv_file_open  = curl_open,
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
@@ -507,7 +507,7 @@ static BlockDriver bdrv_https = {
     .protocol_name   = "https",
 
     .instance_size   = sizeof(BDRVCURLState),
-    .bdrv_open       = curl_open,
+    .bdrv_file_open  = curl_open,
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
@@ -519,7 +519,7 @@ static BlockDriver bdrv_ftp = {
     .protocol_name   = "ftp",
 
     .instance_size   = sizeof(BDRVCURLState),
-    .bdrv_open       = curl_open,
+    .bdrv_file_open  = curl_open,
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
@@ -531,7 +531,7 @@ static BlockDriver bdrv_ftps = {
     .protocol_name   = "ftps",
 
     .instance_size   = sizeof(BDRVCURLState),
-    .bdrv_open       = curl_open,
+    .bdrv_file_open  = curl_open,
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
@@ -543,7 +543,7 @@ static BlockDriver bdrv_tftp = {
     .protocol_name   = "tftp",
 
     .instance_size   = sizeof(BDRVCURLState),
-    .bdrv_open       = curl_open,
+    .bdrv_file_open  = curl_open,
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
block/dmg.c +1 -1
index f4c01c7..d5c1a68 100644
@@ -288,7 +288,7 @@ static BlockDriver bdrv_dmg = {
     .format_name	= "dmg",
     .instance_size	= sizeof(BDRVDMGState),
     .bdrv_probe		= dmg_probe,
-    .bdrv_open		= dmg_open,
+    .bdrv_file_open	= dmg_open,
     .bdrv_read		= dmg_read,
     .bdrv_close		= dmg_close,
 };
block/nbd.c +1 -1
index 7bac38d..a1ec123 100644
@@ -177,7 +177,7 @@ static int64_t nbd_getlength(BlockDriverState *bs)
 static BlockDriver bdrv_nbd = {
     .format_name	= "nbd",
     .instance_size	= sizeof(BDRVNBDState),
-    .bdrv_open		= nbd_open,
+    .bdrv_file_open	= nbd_open,
     .bdrv_read		= nbd_read,
     .bdrv_write		= nbd_write,
     .bdrv_close		= nbd_close,
block/parallels.c +1 -1
index 41b3a7c..b217101 100644
@@ -167,7 +167,7 @@ static BlockDriver bdrv_parallels = {
     .format_name	= "parallels",
     .instance_size	= sizeof(BDRVParallelsState),
     .bdrv_probe		= parallels_probe,
-    .bdrv_open		= parallels_open,
+    .bdrv_file_open	= parallels_open,
     .bdrv_read		= parallels_read,
     .bdrv_close		= parallels_close,
 };
block/qcow.c +30 -37

220 lines not on this page · raw message

block/qcow2-cluster.c +33 -31

188 lines not on this page · raw message

block/qcow2-refcount.c +40 -40

258 lines not on this page · raw message

block/qcow2-snapshot.c +11 -11
index 8ddaea2..2a21c17 100644
@@ -79,7 +79,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
     s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
     for(i = 0; i < s->nb_snapshots; i++) {
         offset = align_offset(offset, 8);
-        if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
+        if (bdrv_pread(bs->file, offset, &h, sizeof(h)) != sizeof(h))
             goto fail;
         offset += sizeof(h);
         sn = s->snapshots + i;
@@ -97,13 +97,13 @@ int qcow2_read_snapshots(BlockDriverState *bs)
         offset += extra_data_size;
 
         sn->id_str = qemu_malloc(id_str_size + 1);
-        if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
+        if (bdrv_pread(bs->file, offset, sn->id_str, id_str_size) != id_str_size)
             goto fail;
         offset += id_str_size;
         sn->id_str[id_str_size] = '\0';
 
         sn->name = qemu_malloc(name_size + 1);
-        if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
+        if (bdrv_pread(bs->file, offset, sn->name, name_size) != name_size)
             goto fail;
         offset += name_size;
         sn->name[name_size] = '\0';
@@ -158,24 +158,24 @@ static int qcow_write_snapshots(BlockDriverState *bs)
         h.id_str_size = cpu_to_be16(id_str_size);
         h.name_size = cpu_to_be16(name_size);
         offset = align_offset(offset, 8);
-        if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
+        if (bdrv_pwrite(bs->file, offset, &h, sizeof(h)) != sizeof(h))
             goto fail;
         offset += sizeof(h);
-        if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
+        if (bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size) != id_str_size)
             goto fail;
         offset += id_str_size;
-        if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
+        if (bdrv_pwrite(bs->file, offset, sn->name, name_size) != name_size)
             goto fail;
         offset += name_size;
     }
 
     /* update the various header fields */
     data64 = cpu_to_be64(snapshots_offset);
-    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
+    if (bdrv_pwrite(bs->file, offsetof(QCowHeader, snapshots_offset),
                     &data64, sizeof(data64)) != sizeof(data64))
         goto fail;
     data32 = cpu_to_be32(s->nb_snapshots);
-    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
+    if (bdrv_pwrite(bs->file, offsetof(QCowHeader, nb_snapshots),
                     &data32, sizeof(data32)) != sizeof(data32))
         goto fail;
 
@@ -284,7 +284,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     for(i = 0; i < s->l1_size; i++) {
         l1_table[i] = cpu_to_be64(s->l1_table[i]);
     }
-    if (bdrv_pwrite(s->hd, sn->l1_table_offset,
+    if (bdrv_pwrite(bs->file, sn->l1_table_offset,
                     l1_table, s->l1_size * sizeof(uint64_t)) !=
         (s->l1_size * sizeof(uint64_t)))
         goto fail;
@@ -332,10 +332,10 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     s->l1_size = sn->l1_size;
     l1_size2 = s->l1_size * sizeof(uint64_t);
     /* copy the snapshot l1 table to the current l1 table */
-    if (bdrv_pread(s->hd, sn->l1_table_offset,
+    if (bdrv_pread(bs->file, sn->l1_table_offset,
                    s->l1_table, l1_size2) != l1_size2)
         goto fail;
-    if (bdrv_pwrite(s->hd, s->l1_table_offset,
+    if (bdrv_pwrite(bs->file, s->l1_table_offset,
                     s->l1_table, l1_size2) != l1_size2)
         goto fail;
     for(i = 0;i < s->l1_size; i++) {
block/qcow2.c +28 -38

221 lines not on this page · raw message

block/qcow2.h +1 -1
index de9397a..5bd08db 100644
@@ -184,7 +184,7 @@ int qcow2_check_refcounts(BlockDriverState *bs);
 /* qcow2-cluster.c functions */
 int qcow2_grow_l1_table(BlockDriverState *bs, int min_size);
 void qcow2_l2_cache_reset(BlockDriverState *bs);
-int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
+int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
 void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
                      uint8_t *out_buf, const uint8_t *in_buf,
                      int nb_sectors, int enc,
block/raw-posix.c +5 -5
index 8f57ab0..598ea19 100644
@@ -773,7 +773,7 @@ static BlockDriver bdrv_file = {
     .protocol_name = "file",
     .instance_size = sizeof(BDRVRawState),
     .bdrv_probe = NULL, /* no probe for protocols */
-    .bdrv_open = raw_open,
+    .bdrv_file_open = raw_open,
     .bdrv_read = raw_read,
     .bdrv_write = raw_write,
     .bdrv_close = raw_close,
@@ -1030,7 +1030,7 @@ static BlockDriver bdrv_host_device = {
     .protocol_name        = "host_device",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device  = hdev_probe_device,
-    .bdrv_open          = hdev_open,
+    .bdrv_file_open     = hdev_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
@@ -1145,7 +1145,7 @@ static BlockDriver bdrv_host_floppy = {
     .protocol_name      = "host_floppy",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device	= floppy_probe_device,
-    .bdrv_open          = floppy_open,
+    .bdrv_file_open     = floppy_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
@@ -1245,7 +1245,7 @@ static BlockDriver bdrv_host_cdrom = {
     .protocol_name      = "host_cdrom",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device	= cdrom_probe_device,
-    .bdrv_open          = cdrom_open,
+    .bdrv_file_open     = cdrom_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
@@ -1368,7 +1368,7 @@ static BlockDriver bdrv_host_cdrom = {
     .protocol_name      = "host_cdrom",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device	= cdrom_probe_device,
-    .bdrv_open          = cdrom_open,
+    .bdrv_file_open     = cdrom_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
block/raw-win32.c +2 -2
index eadebeb..745bbde 100644
@@ -242,7 +242,7 @@ static BlockDriver bdrv_file = {
     .format_name	= "file",
     .protocol_name	= "file",
     .instance_size	= sizeof(BDRVRawState),
-    .bdrv_open		= raw_open,
+    .bdrv_file_open	= raw_open,
     .bdrv_close		= raw_close,
     .bdrv_create	= raw_create,
     .bdrv_flush		= raw_flush,
@@ -399,7 +399,7 @@ static BlockDriver bdrv_host_device = {
     .protocol_name	= "host_device",
     .instance_size	= sizeof(BDRVRawState),
     .bdrv_probe_device	= hdev_probe_device,
-    .bdrv_open		= hdev_open,
+    .bdrv_file_open	= hdev_open,
     .bdrv_close		= raw_close,
     .bdrv_flush		= raw_flush,
 
block/raw.c +18 -45

144 lines not on this page · raw message

block/vdi.c +9 -20
index c91961a..1d257b4 100644
@@ -376,21 +376,15 @@ static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
     return result;
 }
 
-static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
+static int vdi_open(BlockDriverState *bs, int flags)
 {
     BDRVVdiState *s = bs->opaque;
     VdiHeader header;
     size_t bmap_size;
-    int ret;
 
     logout("\n");
 
-    ret = bdrv_file_open(&s->hd, filename, flags);
-    if (ret < 0) {
-        return ret;
-    }
-
-    if (bdrv_read(s->hd, 0, (uint8_t *)&header, 1) < 0) {
+    if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
         goto fail;
     }
 
@@ -442,7 +436,7 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
     bmap_size = header.blocks_in_image * sizeof(uint32_t);
     bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
     s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
-    if (bdrv_read(s->hd, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
+    if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
         goto fail_free_bmap;
     }
 
@@ -452,7 +446,6 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
     qemu_free(s->bmap);
 
  fail:
-    bdrv_delete(s->hd);
     return -1;
 }
 
@@ -607,7 +600,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
         acb->hd_iov.iov_base = (void *)acb->buf;
         acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
         qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-        acb->hd_aiocb = bdrv_aio_readv(s->hd, offset, &acb->hd_qiov,
+        acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov,
                                        n_sectors, vdi_aio_read_cb, acb);
         if (acb->hd_aiocb == NULL) {
             goto done;
@@ -670,7 +663,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
             acb->hd_iov.iov_base = acb->block_buffer;
             acb->hd_iov.iov_len = SECTOR_SIZE;
             qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-            acb->hd_aiocb = bdrv_aio_writev(s->hd, 0, &acb->hd_qiov, 1,
+            acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1,
                                             vdi_aio_write_cb, acb);
             if (acb->hd_aiocb == NULL) {
                 goto done;
@@ -699,7 +692,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
             qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
             logout("will write %u block map sectors starting from entry %u\n",
                    n_sectors, bmap_first);
-            acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
+            acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
                                             n_sectors, vdi_aio_write_cb, acb);
             if (acb->hd_aiocb == NULL) {
                 goto done;
@@ -748,7 +741,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
         acb->hd_iov.iov_base = (void *)block;
         acb->hd_iov.iov_len = s->block_size;
         qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-        acb->hd_aiocb = bdrv_aio_writev(s->hd, offset,
+        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset,
                                         &acb->hd_qiov, s->block_sectors,
                                         vdi_aio_write_cb, acb);
         if (acb->hd_aiocb == NULL) {
@@ -761,7 +754,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
         acb->hd_iov.iov_base = (void *)acb->buf;
         acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
         qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-        acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
+        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
                                         n_sectors, vdi_aio_write_cb, acb);
         if (acb->hd_aiocb == NULL) {
             goto done;
@@ -891,16 +884,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
 
 static void vdi_close(BlockDriverState *bs)
 {
-    BDRVVdiState *s = bs->opaque;
-    logout("\n");
-    bdrv_delete(s->hd);
 }
 
 static void vdi_flush(BlockDriverState *bs)
 {
-    BDRVVdiState *s = bs->opaque;
     logout("\n");
-    bdrv_flush(s->hd);
+    bdrv_flush(bs->file);
 }
 
 
block/vmdk.c +1 -1
index 6fdea1d..5ef4375 100644
@@ -914,7 +914,7 @@ static BlockDriver bdrv_vmdk = {
     .format_name	= "vmdk",
     .instance_size	= sizeof(BDRVVmdkState),
     .bdrv_probe		= vmdk_probe,
-    .bdrv_open		= vmdk_open,
+    .bdrv_file_open	= vmdk_open,
     .bdrv_read		= vmdk_read,
     .bdrv_write		= vmdk_write,
     .bdrv_close		= vmdk_close,
block/vpc.c +12 -20
index 950ad58..f94e469 100644
@@ -150,20 +150,16 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
     return 0;
 }
 
-static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
+static int vpc_open(BlockDriverState *bs, int flags)
 {
     BDRVVPCState *s = bs->opaque;
-    int ret, i;
+    int i;
     struct vhd_footer* footer;
     struct vhd_dyndisk_header* dyndisk_header;
     uint8_t buf[HEADER_SIZE];
     uint32_t checksum;
 
-    ret = bdrv_file_open(&s->hd, filename, flags);
-    if (ret < 0)
-        return ret;
-
-    if (bdrv_pread(s->hd, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
+    if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
         goto fail;
 
     footer = (struct vhd_footer*) s->footer_buf;
@@ -174,7 +170,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
     footer->checksum = 0;
     if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum)
         fprintf(stderr, "block-vpc: The header checksum of '%s' is "
-            "incorrect.\n", filename);
+            "incorrect.\n", bs->filename);
 
     // The visible size of a image in Virtual PC depends on the geometry
     // rather than on the size stored in the footer (the size in the footer
@@ -182,7 +178,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
     bs->total_sectors = (int64_t)
         be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
 
-    if (bdrv_pread(s->hd, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
+    if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
             != HEADER_SIZE)
         goto fail;
 
@@ -199,7 +195,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
     s->pagetable = qemu_malloc(s->max_table_entries * 4);
 
     s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
-    if (bdrv_pread(s->hd, s->bat_offset, s->pagetable,
+    if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
             s->max_table_entries * 4) != s->max_table_entries * 4)
 	    goto fail;
 
@@ -228,7 +224,6 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
 
     return 0;
  fail:
-    bdrv_delete(s->hd);
     return -1;
 }
 
@@ -266,7 +261,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
 
         s->last_bitmap_offset = bitmap_offset;
         memset(bitmap, 0xff, s->bitmap_size);
-        bdrv_pwrite(s->hd, bitmap_offset, bitmap, s->bitmap_size);
+        bdrv_pwrite(bs->file, bitmap_offset, bitmap, s->bitmap_size);
     }
 
 //    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
@@ -316,7 +311,7 @@ static int rewrite_footer(BlockDriverState* bs)
     BDRVVPCState *s = bs->opaque;
     int64_t offset = s->free_data_block_offset;
 
-    ret = bdrv_pwrite(s->hd, offset, s->footer_buf, HEADER_SIZE);
+    ret = bdrv_pwrite(bs->file, offset, s->footer_buf, HEADER_SIZE);
     if (ret < 0)
         return ret;
 
@@ -351,7 +346,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
 
     // Initialize the block's bitmap
     memset(bitmap, 0xff, s->bitmap_size);
-    bdrv_pwrite(s->hd, s->free_data_block_offset, bitmap, s->bitmap_size);
+    bdrv_pwrite(bs->file, s->free_data_block_offset, bitmap, s->bitmap_size);
 
     // Write new footer (the old one will be overwritten)
     s->free_data_block_offset += s->block_size + s->bitmap_size;
@@ -362,7 +357,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
     // Write BAT entry to disk
     bat_offset = s->bat_offset + (4 * index);
     bat_value = be32_to_cpu(s->pagetable[index]);
-    ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4);
+    ret = bdrv_pwrite(bs->file, bat_offset, &bat_value, 4);
     if (ret < 0)
         goto fail;
 
@@ -376,7 +371,6 @@ fail:
 static int vpc_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
-    BDRVVPCState *s = bs->opaque;
     int ret;
     int64_t offset;
 
@@ -386,7 +380,7 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
         if (offset == -1) {
             memset(buf, 0, 512);
         } else {
-            ret = bdrv_pread(s->hd, offset, buf, 512);
+            ret = bdrv_pread(bs->file, offset, buf, 512);
             if (ret != 512)
                 return -1;
         }
@@ -401,7 +395,6 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
 static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     const uint8_t *buf, int nb_sectors)
 {
-    BDRVVPCState *s = bs->opaque;
     int64_t offset;
     int ret;
 
@@ -414,7 +407,7 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
                 return -1;
         }
 
-        ret = bdrv_pwrite(s->hd, offset, buf, 512);
+        ret = bdrv_pwrite(bs->file, offset, buf, 512);
         if (ret != 512)
             return -1;
 
@@ -590,7 +583,6 @@ static void vpc_close(BlockDriverState *bs)
 #ifdef CACHE
     qemu_free(s->pageentry_u8);
 #endif
-    bdrv_delete(s->hd);
 }
 
 static QEMUOptionParameter vpc_create_options[] = {
block/vvfat.c +1 -1
index 66259b4..ce16bbd 100644
@@ -2827,7 +2827,7 @@ static void vvfat_close(BlockDriverState *bs)
 static BlockDriver bdrv_vvfat = {
     .format_name	= "vvfat",
     .instance_size	= sizeof(BDRVVVFATState),
-    .bdrv_open		= vvfat_open,
+    .bdrv_file_open	= vvfat_open,
     .bdrv_read		= vvfat_read,
     .bdrv_write		= vvfat_write,
     .bdrv_close		= vvfat_close,
block_int.h +4 -1
index d4067ff..a3afe63 100644
@@ -51,7 +51,8 @@ struct BlockDriver {
     int instance_size;
     int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
     int (*bdrv_probe_device)(const char *filename);
-    int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
+    int (*bdrv_open)(BlockDriverState *bs, int flags);
+    int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, int flags);
     int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
                      uint8_t *buf, int nb_sectors);
     int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
@@ -155,6 +156,8 @@ struct BlockDriverState {
     int media_changed;
 
     BlockDriverState *backing_hd;
+    BlockDriverState *file;
+
     /* async read/write emulation */
 
     void *sync_aiocb;
Signature · 1 line
1.6.6.1
author
#5 lore raw

PATCH 5/18 block: bdrv_has_zero_init

In reply to Kevin Wolf

This fixes the problem that qemu-img's use of no_zero_init only considered the no_zero_init flag of the format driver, but not of the underlying protocols.

Between the raw/file split and this fix, converting to host devices is broken.

---
 block.c    |   13 +++++++++++++
 block.h    |    1 +
 qemu-img.c |    6 ++++--
 3 files changed, 18 insertions(+), 2 deletions(-)
block.c +13 -0
index eb1d562..56835af 100644
@@ -1282,6 +1282,19 @@ void bdrv_flush_all(void)
     }
 }
 
+int bdrv_has_zero_init(BlockDriverState *bs)
+{
+    assert(bs->drv);
+
+    if (bs->drv->no_zero_init) {
+        return 0;
+    } else if (bs->file) {
+        return bdrv_has_zero_init(bs->file);
+    }
+
+    return 1;
+}
+
 /*
  * Returns true iff the specified sector is present in the disk image. Drivers
  * not implementing the functionality are assumed to not support backing files,
block.h +1 -0
index f58edf1..f87d24e 100644
@@ -122,6 +122,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
 void bdrv_flush(BlockDriverState *bs);
 void bdrv_flush_all(void);
 
+int bdrv_has_zero_init(BlockDriverState *bs);
 int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
 	int *pnum);
 
qemu-img.c +4 -2
index 7203b8b..74311a5 100644
@@ -732,6 +732,8 @@ static int img_convert(int argc, char **argv)
         /* signal EOF to align */
         bdrv_write_compressed(out_bs, 0, NULL, 0);
     } else {
+        int has_zero_init = bdrv_has_zero_init(out_bs);
+
         sector_num = 0; // total number of sectors converted so far
         for(;;) {
             nb_sectors = total_sectors - sector_num;
@@ -755,7 +757,7 @@ static int img_convert(int argc, char **argv)
             if (n > bs_offset + bs_sectors - sector_num)
                 n = bs_offset + bs_sectors - sector_num;
 
-            if (!drv->no_zero_init) {
+            if (has_zero_init) {
                 /* If the output image is being created as a copy on write image,
                    assume that sectors which are unallocated in the input image
                    are present in both the output's and input's base images (no
@@ -788,7 +790,7 @@ static int img_convert(int argc, char **argv)
                    If the output is to a host device, we also write out
                    sectors that are entirely 0, since whatever data was
                    already there is garbage, not 0s. */
-                if (drv->no_zero_init || out_baseimg ||
+                if (!has_zero_init || out_baseimg ||
                     is_allocated_sectors(buf1, n, &n1)) {
                     if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
                         error("error while writing");
Signature · 1 line
1.6.6.1
author
#6 lore raw

PATCH 6/18 vmdk: Fix COW

In reply to Kevin Wolf

When trying to do COW, VMDK wrote the data back to the backing file. This problem was revealed by the patch that made backing files read-only. This patch does not only fix the problem, but also simplifies the VMDK code a bit.

This fixes the backing file qemu-iotests cases for VMDK.

---
 block/vmdk.c |   35 +++++++++++------------------------
 1 files changed, 11 insertions(+), 24 deletions(-)
block/vmdk.c +11 -24
index 5ef4375..ae34121 100644
@@ -87,14 +87,6 @@ typedef struct VmdkMetaData {
     int valid;
 } VmdkMetaData;
 
-typedef struct ActiveBDRVState{
-    BlockDriverState *hd;            // active image handler
-    uint64_t cluster_offset;         // current write offset
-}ActiveBDRVState;
-
-static ActiveBDRVState activeBDRV;
-
-
 static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     uint32_t magic;
@@ -492,30 +484,28 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
 static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
                              uint64_t offset, int allocate)
 {
-    uint64_t parent_cluster_offset;
     BDRVVmdkState *s = bs->opaque;
     uint8_t  whole_grain[s->cluster_sectors*512];        // 128 sectors * 512 bytes each = grain size 64KB
 
     // 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) {
-        BDRVVmdkState *ps = bs->backing_hd->opaque;
+        int ret;
 
         if (!vmdk_is_cid_valid(bs))
             return -1;
 
-        parent_cluster_offset = get_cluster_offset(bs->backing_hd, NULL,
-            offset, allocate);
-
-        if (parent_cluster_offset) {
-            BDRVVmdkState *act_s = activeBDRV.hd->opaque;
-
-            if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512)
-                return -1;
+        ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
+            s->cluster_sectors);
+        if (ret < 0) {
+            return -1;
+        }
 
-            //Write grain only into the active image
-            if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain))
-                return -1;
+        //Write grain only into the active image
+        ret = bdrv_write(s->hd, cluster_offset, whole_grain,
+            s->cluster_sectors);
+        if (ret < 0) {
+            return -1;
         }
     }
     return 0;
@@ -601,9 +591,6 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
             cluster_offset >>= 9;
             tmp = cpu_to_le32(cluster_offset);
             l2_table[l2_index] = tmp;
-            // Save the active image state
-            activeBDRV.cluster_offset = cluster_offset;
-            activeBDRV.hd = bs;
         }
         /* First of all we write grain itself, to avoid race condition
          * that may to corrupt the image.
Signature · 1 line
1.6.6.1
author
#7 lore raw

PATCH 7/18 vmdk: Clean up backing file handling

In reply to Kevin Wolf

VMDK is doing interesting things when it needs to open a backing file. This patch changes that part to look more like in other drivers. The nice side effect is that the file name isn't needed any more in the open function.

---
 block/vmdk.c |   58 +++++++++-------------------------------------------------
 1 files changed, 9 insertions(+), 49 deletions(-)
block/vmdk.c +9 -49
index ae34121..e44769b 100644
@@ -76,7 +76,6 @@ typedef struct BDRVVmdkState {
 
     unsigned int cluster_sectors;
     uint32_t parent_cid;
-    int is_parent;
 } BDRVVmdkState;
 
 typedef struct VmdkMetaData {
@@ -338,19 +337,11 @@ fail:
     return ret;
 }
 
-static void vmdk_parent_close(BlockDriverState *bs)
-{
-    if (bs->backing_hd)
-        bdrv_close(bs->backing_hd);
-}
-
-static int parent_open = 0;
-static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
+static int vmdk_parent_open(BlockDriverState *bs)
 {
     BDRVVmdkState *s = bs->opaque;
     char *p_name;
     char desc[DESC_SIZE];
-    char parent_img_name[1024];
 
     /* the descriptor offset = 0x200 */
     if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
@@ -358,7 +349,6 @@ static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
 
     if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) {
         char *end_name;
-        struct stat file_buf;
 
         p_name += sizeof("parentFileNameHint") + 1;
         if ((end_name = strchr(p_name,'\"')) == NULL)
@@ -367,24 +357,6 @@ static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
             return -1;
 
         pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
-        if (stat(bs->backing_file, &file_buf) != 0) {
-            path_combine(parent_img_name, sizeof(parent_img_name),
-                         filename, bs->backing_file);
-        } else {
-            pstrcpy(parent_img_name, sizeof(parent_img_name),
-                    bs->backing_file);
-        }
-
-        bs->backing_hd = bdrv_new("");
-        if (!bs->backing_hd) {
-            failure:
-            bdrv_close(s->hd);
-            return -1;
-        }
-        parent_open = 1;
-        if (bdrv_open(bs->backing_hd, parent_img_name, 0, NULL) < 0)
-            goto failure;
-        parent_open = 0;
     }
 
     return 0;
@@ -396,11 +368,6 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
     uint32_t magic;
     int l1_size, i, ret;
 
-    if (parent_open) {
-        /* Parent must be opened as RO, no RDWR. */
-        flags = 0;
-    }
-
     ret = bdrv_file_open(&s->hd, filename, flags);
     if (ret < 0)
         return ret;
@@ -436,13 +403,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
         s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
         s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
 
-        if (parent_open)
-            s->is_parent = 1;
-        else
-            s->is_parent = 0;
-
         // try to open parent images, if exist
-        if (vmdk_parent_open(bs, filename) != 0)
+        if (vmdk_parent_open(bs) != 0)
             goto fail;
         // write the CID once after the image creation
         s->parent_cid = vmdk_read_cid(bs,1);
@@ -583,15 +545,15 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
     if (!cluster_offset) {
         if (!allocate)
             return 0;
+
         // Avoid the L2 tables update for the images that have snapshots.
-        if (!s->is_parent) {
-            cluster_offset = bdrv_getlength(s->hd);
-            bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
+        cluster_offset = bdrv_getlength(s->hd);
+        bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
+
+        cluster_offset >>= 9;
+        tmp = cpu_to_le32(cluster_offset);
+        l2_table[l2_index] = tmp;
 
-            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
          * that may to corrupt the image.
          * This problem may occur because of insufficient space on host disk
@@ -866,8 +828,6 @@ static void vmdk_close(BlockDriverState *bs)
 
     qemu_free(s->l1_table);
     qemu_free(s->l2_cache);
-    // try to close parent image, if exist
-    vmdk_parent_close(s->hd);
     bdrv_delete(s->hd);
 }
 
Signature · 1 line
1.6.6.1
author
#8 lore raw

PATCH 8/18 vmdk: Convert to bdrv_open

In reply to Kevin Wolf

It's a format driver, so implement bdrv_open instead of bdrv_file_open.

---
 block/vmdk.c |   51 +++++++++++++++++++++------------------------------
 1 files changed, 21 insertions(+), 30 deletions(-)
block/vmdk.c +21 -30
index e44769b..e659908 100644
@@ -108,14 +108,13 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
 
 static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
 {
-    BDRVVmdkState *s = bs->opaque;
     char desc[DESC_SIZE];
     uint32_t cid;
     const char *p_name, *cid_str;
     size_t cid_str_size;
 
     /* the descriptor offset = 0x200 */
-    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
         return 0;
 
     if (parent) {
@@ -136,12 +135,11 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
 
 static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
 {
-    BDRVVmdkState *s = bs->opaque;
     char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
     char *p_name, *tmp_str;
 
     /* the descriptor offset = 0x200 */
-    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
         return -1;
 
     tmp_str = strstr(desc,"parentCID");
@@ -152,7 +150,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
         pstrcat(desc, sizeof(desc), tmp_desc);
     }
 
-    if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+    if (bdrv_pwrite(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
         return -1;
     return 0;
 }
@@ -339,12 +337,11 @@ fail:
 
 static int vmdk_parent_open(BlockDriverState *bs)
 {
-    BDRVVmdkState *s = bs->opaque;
     char *p_name;
     char desc[DESC_SIZE];
 
     /* the descriptor offset = 0x200 */
-    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
         return -1;
 
     if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) {
@@ -362,23 +359,20 @@ static int vmdk_parent_open(BlockDriverState *bs)
     return 0;
 }
 
-static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
+static int vmdk_open(BlockDriverState *bs, int flags)
 {
     BDRVVmdkState *s = bs->opaque;
     uint32_t magic;
-    int l1_size, i, ret;
+    int l1_size, i;
 
-    ret = bdrv_file_open(&s->hd, filename, flags);
-    if (ret < 0)
-        return ret;
-    if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
+    if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic))
         goto fail;
 
     magic = be32_to_cpu(magic);
     if (magic == VMDK3_MAGIC) {
         VMDK3Header header;
 
-        if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(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;
@@ -390,7 +384,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
     } else if (magic == VMDK4_MAGIC) {
         VMDK4Header header;
 
-        if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(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);
@@ -415,7 +409,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
     /* read the L1 table */
     l1_size = s->l1_size * sizeof(uint32_t);
     s->l1_table = qemu_malloc(l1_size);
-    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != 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]);
@@ -423,7 +417,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
 
     if (s->l1_backup_table_offset) {
         s->l1_backup_table = qemu_malloc(l1_size);
-        if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != 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]);
@@ -436,7 +430,6 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
     qemu_free(s->l1_backup_table);
     qemu_free(s->l1_table);
     qemu_free(s->l2_cache);
-    bdrv_delete(s->hd);
     return -1;
 }
 
@@ -464,7 +457,7 @@ static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
         }
 
         //Write grain only into the active image
-        ret = bdrv_write(s->hd, cluster_offset, whole_grain,
+        ret = bdrv_write(bs->file, cluster_offset, whole_grain,
             s->cluster_sectors);
         if (ret < 0) {
             return -1;
@@ -478,13 +471,13 @@ static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
     BDRVVmdkState *s = bs->opaque;
 
     /* update L2 table */
-    if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
+    if (bdrv_pwrite(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
                     &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
         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(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
+        if (bdrv_pwrite(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
                         &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
             return -1;
     }
@@ -532,7 +525,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
         }
     }
     l2_table = s->l2_cache + (min_index * s->l2_size);
-    if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
+    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;
 
@@ -547,8 +540,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
             return 0;
 
         // Avoid the L2 tables update for the images that have snapshots.
-        cluster_offset = bdrv_getlength(s->hd);
-        bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
+        cluster_offset = bdrv_getlength(bs->file);
+        bdrv_truncate(bs->file, cluster_offset + (s->cluster_sectors << 9));
 
         cluster_offset >>= 9;
         tmp = cpu_to_le32(cluster_offset);
@@ -615,7 +608,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
                 memset(buf, 0, 512 * n);
             }
         } else {
-            if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
+            if(bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
                 return -1;
         }
         nb_sectors -= n;
@@ -651,7 +644,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
         if (!cluster_offset)
             return -1;
 
-        if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
+        if (bdrv_pwrite(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
             return -1;
         if (m_data.valid) {
             /* update L2 tables */
@@ -828,13 +821,11 @@ static void vmdk_close(BlockDriverState *bs)
 
     qemu_free(s->l1_table);
     qemu_free(s->l2_cache);
-    bdrv_delete(s->hd);
 }
 
 static void vmdk_flush(BlockDriverState *bs)
 {
-    BDRVVmdkState *s = bs->opaque;
-    bdrv_flush(s->hd);
+    bdrv_flush(bs->file);
 }
 
 
@@ -861,7 +852,7 @@ static BlockDriver bdrv_vmdk = {
     .format_name	= "vmdk",
     .instance_size	= sizeof(BDRVVmdkState),
     .bdrv_probe		= vmdk_probe,
-    .bdrv_file_open	= vmdk_open,
+    .bdrv_open      = vmdk_open,
     .bdrv_read		= vmdk_read,
     .bdrv_write		= vmdk_write,
     .bdrv_close		= vmdk_close,
Signature · 1 line
1.6.6.1
author
#9 lore raw

PATCH 9/18 block: Set backing_hd to NULL after deleting it

In reply to Kevin Wolf

From: Stefan Hajnoczi <[email protected]>

It is safer to set backing_hd to NULL after deleting it so that any use after deletion is obvious during development. Happy segfaulting!

This patch should be applied after Kevin Wolf's "vmdk: Convert to bdrv_open" so that vmdk does not segfault on close.

---
 block.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
block.c +3 -1
index 56835af..b318355 100644
@@ -589,8 +589,10 @@ unlink_and_fail:
 void bdrv_close(BlockDriverState *bs)
 {
     if (bs->drv) {
-        if (bs->backing_hd)
+        if (bs->backing_hd) {
             bdrv_delete(bs->backing_hd);
+            bs->backing_hd = NULL;
+        }
         bs->drv->bdrv_close(bs);
         qemu_free(bs->opaque);
 #ifdef _WIN32
Signature · 1 line
1.6.6.1
author
#10 lore raw

PATCH 10/18 qcow2: Avoid shadowing variable in alloc_clusters_noref()

In reply to Kevin Wolf

From: Stefan Hajnoczi <[email protected]>

The i loop iterator is shadowed by the next free cluster index. Both using the variable name 'i' makes the code harder to read.

---
 block/qcow2-refcount.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
block/qcow2-refcount.c +2 -2
index 2661493..95491d3 100644
@@ -556,8 +556,8 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
     nb_clusters = size_to_clusters(s, size);
 retry:
     for(i = 0; i < nb_clusters; i++) {
-        int64_t i = s->free_cluster_index++;
-        if (get_refcount(bs, i) != 0)
+        int64_t next_cluster_index = s->free_cluster_index++;
+        if (get_refcount(bs, next_cluster_index) != 0)
             goto retry;
     }
 #ifdef DEBUG_ALLOC2
Signature · 1 line
1.6.6.1
author
#11 lore raw

PATCH 11/18 raw-posix: Use pread/pwrite instead of lseek+read/write

In reply to Kevin Wolf

From: Stefan Hajnoczi <[email protected]>

This patch combines the lseek+read/write calls to use pread/pwrite instead. This will result in fewer system calls and is already used by AIO.

Thanks to Jan Kiszka <[email protected]> for identifying excessive lseek and Christoph Hellwig <[email protected]> for confirming that this approach should work.

---
 block/raw-posix.c |   37 ++++---------------------------------
 1 files changed, 4 insertions(+), 33 deletions(-)
block/raw-posix.c +4 -33
index 598ea19..7541ed2 100644
@@ -105,7 +105,6 @@
 typedef struct BDRVRawState {
     int fd;
     int type;
-    unsigned int lseek_err_cnt;
     int open_flags;
 #if defined(__linux__)
     /* linux floppy specific */
@@ -134,8 +133,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
     BDRVRawState *s = bs->opaque;
     int fd, ret;
 
-    s->lseek_err_cnt = 0;
-
     s->open_flags = open_flags | O_BINARY;
     s->open_flags &= ~O_ACCMODE;
     if (bdrv_flags & BDRV_O_RDWR) {
@@ -243,19 +240,7 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
     if (ret < 0)
         return ret;
 
-    if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
-        ++(s->lseek_err_cnt);
-        if(s->lseek_err_cnt <= 10) {
-            DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
-                              "] lseek failed : %d = %s\n",
-                              s->fd, bs->filename, offset, buf, count,
-                              bs->total_sectors, errno, strerror(errno));
-        }
-        return -1;
-    }
-    s->lseek_err_cnt=0;
-
-    ret = read(s->fd, buf, count);
+    ret = pread(s->fd, buf, count, offset);
     if (ret == count)
         goto label__raw_read__success;
 
@@ -276,12 +261,10 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
 
     /* Try harder for CDrom. */
     if (bs->type == BDRV_TYPE_CDROM) {
-        lseek(s->fd, offset, SEEK_SET);
-        ret = read(s->fd, buf, count);
+        ret = pread(s->fd, buf, count, offset);
         if (ret == count)
             goto label__raw_read__success;
-        lseek(s->fd, offset, SEEK_SET);
-        ret = read(s->fd, buf, count);
+        ret = pread(s->fd, buf, count, offset);
         if (ret == count)
             goto label__raw_read__success;
 
@@ -313,19 +296,7 @@ static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset,
     if (ret < 0)
         return -errno;
 
-    if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
-        ++(s->lseek_err_cnt);
-        if(s->lseek_err_cnt) {
-            DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%"
-                              PRId64 "] lseek failed : %d = %s\n",
-                              s->fd, bs->filename, offset, buf, count,
-                              bs->total_sectors, errno, strerror(errno));
-        }
-        return -EIO;
-    }
-    s->lseek_err_cnt = 0;
-
-    ret = write(s->fd, buf, count);
+    ret = pwrite(s->fd, buf, count, offset);
     if (ret == count)
         goto label__raw_write__success;
 
Signature · 1 line
1.6.6.1
author
#12 lore raw

PATCH 12/18 block: Cache total_sectors to reduce bdrv_getlength calls

In reply to Kevin Wolf

From: Stefan Hajnoczi <[email protected]>

The BlockDriver bdrv_getlength function is called from the I/O code path when checking that the request falls within the device. Unfortunately this involves an lseek system call in the raw protocol; every read or write request will incur this lseek cost.

Jan Kiszka <[email protected]> identified this issue and its latency overhead. This patch caches device length in the existing total_sectors variable so lseek calls can be avoided for fixed size devices.

Growable devices fall back to the full bdrv_getlength code path because I have not added logic to detect extending the size of the device in a write.

---
 block.c |   43 ++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 38 insertions(+), 5 deletions(-)
block.c +38 -5
index b318355..91fecab 100644
@@ -352,6 +352,26 @@ static BlockDriver *find_image_format(const char *filename)
     return drv;
 }
 
+/**
+ * Set the current 'total_sectors' value
+ */
+static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
+{
+    BlockDriver *drv = bs->drv;
+
+    /* query actual device if possible, otherwise just trust the hint */
+    if (drv->bdrv_getlength) {
+        int64_t length = drv->bdrv_getlength(bs);
+        if (length < 0) {
+            return length;
+        }
+        hint = length >> BDRV_SECTOR_BITS;
+    }
+
+    bs->total_sectors = hint;
+    return 0;
+}
+
 /*
  * Common part for opening disk images and files
  */
@@ -363,6 +383,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
     assert(drv != NULL);
 
     bs->file = NULL;
+    bs->total_sectors = 0;
     bs->is_temporary = 0;
     bs->encrypted = 0;
     bs->valid_key = 0;
@@ -416,9 +437,12 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
     }
 
     bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
-    if (drv->bdrv_getlength) {
-        bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+
+    ret = refresh_total_sectors(bs, bs->total_sectors);
+    if (ret < 0) {
+        goto free_and_fail;
     }
+
 #ifndef _WIN32
     if (bs->is_temporary) {
         unlink(filename);
@@ -959,13 +983,18 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
 int bdrv_truncate(BlockDriverState *bs, int64_t offset)
 {
     BlockDriver *drv = bs->drv;
+    int ret;
     if (!drv)
         return -ENOMEDIUM;
     if (!drv->bdrv_truncate)
         return -ENOTSUP;
     if (bs->read_only)
         return -EACCES;
-    return drv->bdrv_truncate(bs, offset);
+    ret = drv->bdrv_truncate(bs, offset);
+    if (ret == 0) {
+        ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
+    }
+    return ret;
 }
 
 /**
@@ -976,8 +1005,12 @@ int64_t bdrv_getlength(BlockDriverState *bs)
     BlockDriver *drv = bs->drv;
     if (!drv)
         return -ENOMEDIUM;
-    if (!drv->bdrv_getlength) {
-        /* legacy mode */
+
+    /* Fixed size devices use the total_sectors value for speed instead of
+       issuing a length query (like lseek) on each call.  Also, legacy block
+       drivers don't provide a bdrv_getlength function and must use
+       total_sectors. */
+    if (!bs->growable || !drv->bdrv_getlength) {
         return bs->total_sectors * BDRV_SECTOR_SIZE;
     }
     return drv->bdrv_getlength(bs);
Signature · 1 line
1.6.6.1
author
#13 lore raw

PATCH 13/18 qemu-img: Add 'resize' command to grow/shrink disk images

In reply to Kevin Wolf

From: Stefan Hajnoczi <[email protected]>

This patch adds a 'resize' command to grow/shrink disk images. This allows changing the size of disk images without copying to a new image file. Currently only raw files support resize.

---
 qemu-img-cmds.hx |    6 +++
 qemu-img.c       |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-img.texi    |   12 +++++++
 3 files changed, 110 insertions(+), 0 deletions(-)
qemu-img-cmds.hx +6 -0
index f96876a..c079019 100644
@@ -49,5 +49,11 @@ DEF("rebase", img_rebase,
     "rebase [-f fmt] [-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}
+ETEXI
+
+DEF("resize", img_resize,
+    "resize filename [+ | -]size")
+STEXI
+@item rebase @var{filename} [+ | -]@var{size}
 @end table
 ETEXI
qemu-img.c +92 -0

98 lines not on this page · raw message

qemu-img.texi +12 -0
index ac97854..c1b1f27 100644
@@ -106,6 +106,18 @@ they are displayed too.
 @item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot} ] @var{filename}
 
 List, apply, create or delete snapshots in image @var{filename}.
+
+@item resize @var{filename} [+ | -]@var{size}
+
+Change the disk image as if it had been created with @var{size}.
+
+Before using this command to shrink a disk image, you MUST use file system and
+partitioning tools inside the VM to reduce allocated file systems and partition
+sizes accordingly.  Failure to do so will result in data loss!
+
+After using this command to grow a disk image, you must use file system and
+partitioning tools inside the VM to actually begin using the new space on the
+device.
 @end table
 
 Supported image file formats:
Signature · 1 line
1.6.6.1
author
#14 lore raw

PATCH 14/18 qcow2: Remove abort on free_clusters failure

In reply to Kevin Wolf

While it's true that during regular operation free_clusters failure would be a bug, an I/O error can always happen. There's no need to kill the VM, the worst thing that can happen (and it will) is that we leak some clusters.

---
 block/qcow2-refcount.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
block/qcow2-refcount.c +1 -1
index 95491d3..744107c 100644
@@ -638,7 +638,7 @@ void qcow2_free_clusters(BlockDriverState *bs,
     ret = update_refcount(bs, offset, size, -1);
     if (ret < 0) {
         fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
-        abort();
+        /* TODO Remember the clusters to free them later and avoid leaking */
     }
 }
 
Signature · 1 line
1.6.6.1
author
#15 lore raw

PATCH 15/18 qcow2: Implement bdrv_truncate() for growing images

In reply to Kevin Wolf

From: Stefan Hajnoczi <[email protected]>

This patch adds the ability to grow qcow2 images in-place using bdrv_truncate(). This enables qemu-img resize command support for qcow2.

Snapshots are not supported and bdrv_truncate() will return -ENOTSUP. The notion of resizing an image with snapshots could lead to confusion:
users may expect snapshots to remain unchanged, but this is not possible with the current qcow2 on-disk format where the header.size field is global instead of per-snapshot. Others may expect snapshots to change size along with the current image data. I think it is safest to not support snapshots and perhaps add behavior later if there is a consensus.

Backing images continue to work. If the image is now larger than its backing image, zeroes are read when accessing beyond the end of the backing image.

---
 block/qcow2.c |   46 ++++++++++++++++++++++++++++++++++++++++++----
 block/qcow2.h |    6 ++++++
 2 files changed, 48 insertions(+), 4 deletions(-)
block/qcow2.c +42 -4
index 4fa3ff9..21ed6f8 100644
@@ -140,7 +140,7 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
 static int qcow_open(BlockDriverState *bs, int flags)
 {
     BDRVQcowState *s = bs->opaque;
-    int len, i, shift;
+    int len, i;
     QCowHeader header;
     uint64_t ext_end;
 
@@ -188,8 +188,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
 
     /* read the level 1 table */
     s->l1_size = header.l1_size;
-    shift = s->cluster_bits + s->l2_bits;
-    s->l1_vm_state_index = (header.size + (1LL << shift) - 1) >> shift;
+    s->l1_vm_state_index = size_to_l1(s, header.size);
     /* the L1 table must contain at least enough entries to put
        header.size bytes */
     if (s->l1_size < s->l1_vm_state_index)
@@ -851,6 +850,43 @@ static int qcow_make_empty(BlockDriverState *bs)
     return 0;
 }
 
+static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, new_l1_size;
+
+    if (offset & 511) {
+        return -EINVAL;
+    }
+
+    /* cannot proceed if image has snapshots */
+    if (s->nb_snapshots) {
+        return -ENOTSUP;
+    }
+
+    /* shrinking is currently not supported */
+    if (offset < bs->total_sectors * 512) {
+        return -ENOTSUP;
+    }
+
+    new_l1_size = size_to_l1(s, offset);
+    ret = qcow2_grow_l1_table(bs, new_l1_size);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* write updated header.size */
+    offset = cpu_to_be64(offset);
+    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, size),
+                      &offset, sizeof(uint64_t));
+    if (ret < 0) {
+        return ret;
+    }
+
+    s->l1_vm_state_index = new_l1_size;
+    return 0;
+}
+
 /* XXX: put compressed sectors first, then all the cluster aligned
    tables to avoid losing bytes in alignment */
 static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
@@ -1050,7 +1086,9 @@ static BlockDriver bdrv_qcow2 = {
     .bdrv_aio_readv	= qcow_aio_readv,
     .bdrv_aio_writev	= qcow_aio_writev,
     .bdrv_aio_flush	= qcow_aio_flush,
-    .bdrv_write_compressed = qcow_write_compressed,
+
+    .bdrv_truncate          = qcow2_truncate,
+    .bdrv_write_compressed  = qcow_write_compressed,
 
     .bdrv_snapshot_create   = qcow2_snapshot_create,
     .bdrv_snapshot_goto     = qcow2_snapshot_goto,
block/qcow2.h +6 -0
index 5bd08db..01053b7 100644
@@ -150,6 +150,12 @@ static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
     return (size + (s->cluster_size - 1)) >> s->cluster_bits;
 }
 
+static inline int size_to_l1(BDRVQcowState *s, int64_t size)
+{
+    int shift = s->cluster_bits + s->l2_bits;
+    return (size + (1ULL << shift) - 1) >> shift;
+}
+
 static inline int64_t align_offset(int64_t offset, int n)
 {
     offset = (offset + n - 1) & ~(n - 1);
Signature · 1 line
1.6.6.1
author
#16 lore raw

PATCH 16/18 block: Add wr_highest_sector blockstat

In reply to Kevin Wolf

This adds the wr_highest_sector blockstat which implements what is generally known as the high watermark. It is the highest offset of a sector written to the respective BlockDriverState since it has been opened.

The query-blockstat QMP command is extended to add this value to the result, and also to add the statistics of the underlying protocol in a new "parent" field. Note that to get the "high watermark" of a qcow2 image, you need to look into the wr_highest_sector field of the parent (which can be a file, a host_device, ...). The wr_highest_sector of the qcow2 BlockDriverState itself is the highest offset on the _virtual_ disk that the guest has written to.

---
 block.c     |   73 ++++++++++++++++++++++++++++++++++++++++++++++------------
 block_int.h |    1 +
 2 files changed, 59 insertions(+), 15 deletions(-)
block.c +58 -15
index 91fecab..f463ec4 100644
@@ -880,6 +880,10 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
         set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
     }
 
+    if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
+        bs->wr_highest_sector = sector_num + nb_sectors - 1;
+    }
+
     return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
 }
 
@@ -1530,6 +1534,35 @@ void bdrv_stats_print(Monitor *mon, const QObject *data)
     qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
 }
 
+static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
+{
+    QObject *res;
+    QDict *dict;
+
+    res = qobject_from_jsonf("{ 'stats': {"
+                             "'rd_bytes': %" PRId64 ","
+                             "'wr_bytes': %" PRId64 ","
+                             "'rd_operations': %" PRId64 ","
+                             "'wr_operations': %" PRId64 ","
+                             "'wr_highest_offset': %" PRId64
+                             "} }",
+                             bs->rd_bytes, bs->wr_bytes,
+                             bs->rd_ops, bs->wr_ops,
+                             bs->wr_highest_sector * 512);
+    dict  = qobject_to_qdict(res);
+
+    if (*bs->device_name) {
+        qdict_put(dict, "device", qstring_from_str(bs->device_name));
+    }
+
+    if (bs->file) {
+        QObject *parent = bdrv_info_stats_bs(bs->file);
+        qdict_put_obj(dict, "parent", parent);
+    }
+
+    return res;
+}
+
 /**
  * bdrv_info_stats(): show block device statistics
  *
@@ -1544,19 +1577,34 @@ void bdrv_stats_print(Monitor *mon, const QObject *data)
  *     - "wr_bytes": bytes written
  *     - "rd_operations": read operations
  *     - "wr_operations": write operations
- * 
+ *     - "wr_highest_offset": Highest offset of a sector written since the
+ *       BlockDriverState has been opened
+ *     - "parent": Contains recursively the statistics of the underlying
+ *       protocol (e.g. the host file for a qcow2 image). If there is no
+ *       underlying protocol, this field is omitted.
+ *
  * Example:
  *
  * [ { "device": "ide0-hd0",
  *               "stats": { "rd_bytes": 512,
  *                          "wr_bytes": 0,
  *                          "rd_operations": 1,
- *                          "wr_operations": 0 } },
+ *                          "wr_operations": 0,
+ *                          "wr_highest_offset": 0,
+ *                          "parent": {
+ *                              "stats": { "rd_bytes": 1024,
+ *                                         "wr_bytes": 0,
+ *                                         "rd_operations": 2,
+ *                                         "wr_operations": 0,
+ *                                         "wr_highest_offset": 0,
+ *                              }
+ *                          } } },
  *   { "device": "ide1-cd0",
  *               "stats": { "rd_bytes": 0,
  *                          "wr_bytes": 0,
  *                          "rd_operations": 0,
- *                          "wr_operations": 0 } } ]
+ *                          "wr_operations": 0,
+ *                          "wr_highest_offset": 0 } },
  */
 void bdrv_info_stats(Monitor *mon, QObject **ret_data)
 {
@@ -1567,15 +1615,7 @@ void bdrv_info_stats(Monitor *mon, QObject **ret_data)
     devices = qlist_new();
 
     QTAILQ_FOREACH(bs, &bdrv_states, list) {
-        obj = qobject_from_jsonf("{ 'device': %s, 'stats': {"
-                                 "'rd_bytes': %" PRId64 ","
-                                 "'wr_bytes': %" PRId64 ","
-                                 "'rd_operations': %" PRId64 ","
-                                 "'wr_operations': %" PRId64
-                                 "} }",
-                                 bs->device_name,
-                                 bs->rd_bytes, bs->wr_bytes,
-                                 bs->rd_ops, bs->wr_ops);
+        obj = bdrv_info_stats_bs(bs);
         qlist_append_obj(devices, obj);
     }
 
@@ -1834,9 +1874,12 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                cb, opaque);
 
     if (ret) {
-	/* Update stats even though technically transfer has not happened. */
-	bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
-	bs->wr_ops ++;
+        /* Update stats even though technically transfer has not happened. */
+        bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
+        bs->wr_ops ++;
+        if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
+            bs->wr_highest_sector = sector_num + nb_sectors - 1;
+        }
     }
 
     return ret;
block_int.h +1 -0
index a3afe63..1a7240c 100644
@@ -167,6 +167,7 @@ struct BlockDriverState {
     uint64_t wr_bytes;
     uint64_t rd_ops;
     uint64_t wr_ops;
+    uint64_t wr_highest_sector;
 
     /* Whether the disk can expand beyond total_sectors */
     int growable;
Signature · 1 line
1.6.6.1
author
#17 lore raw

PATCH 17/18 qemu-img rebase: Fix output image corruption

In reply to Kevin Wolf

qemu-img rebase must always give clusters in the COW file priority over those in the backing file. As it failed to use number of non-allocated clusters but assumed the maximum, it was possible that allocated clusters were taken from the backing file instead, leading to a corrupted output image.

---
 qemu-img.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
qemu-img.c +3 -3
index c21d999..d3c30a7 100644
@@ -1136,7 +1136,7 @@ static int img_rebase(int argc, char **argv)
     if (!unsafe) {
         uint64_t num_sectors;
         uint64_t sector;
-        int n, n1;
+        int n;
         uint8_t * buf_old;
         uint8_t * buf_new;
 
@@ -1155,8 +1155,8 @@ static int img_rebase(int argc, char **argv)
             }
 
             /* If the cluster is allocated, we don't need to take action */
-            if (bdrv_is_allocated(bs, sector, n, &n1)) {
-                n = n1;
+            ret = bdrv_is_allocated(bs, sector, n, &n);
+            if (ret) {
                 continue;
             }
 
Signature · 1 line
1.6.6.1
author
#18 lore raw

PATCH 18/18 block: Release allocated options after bdrv_open

In reply to Kevin Wolf

From: Jan Kiszka <[email protected]>

They aren't used afterwards nor supposed to be stored by a bdrv_create handler.

---
 block.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
block.c +1 -0
index f463ec4..48305b7 100644
@@ -540,6 +540,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         }
 
         ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
+        free_option_parameters(options);
         if (ret < 0) {
             return ret;
         }
Signature · 1 line
1.6.6.1
#19 lore raw
In reply to Kevin Wolf
Quoted 9 lines · Kevin Wolf

Hi Anthony,

this is the second part of the block patches in my queue that I promised in the pull request last week. I also included the high watermark patch even if it didn't sit on the list for a very long time - but the people that I expected to comment on it have already done so, either on the list or internally.

Kevin

Quoted 8 lines

The following changes since commit 9ed7b059ef776a3921cfd085e891f45076922542:
Amit Shah (1):
virtio-serial: Implement flow control for individual ports

are available in the git repository at:

git://repo.or.cz/qemu/kevin.git for-anthony

Pulled. Thanks.

Regards,

Anthony Liguori

Quoted 57 lines

Christoph Hellwig (1):
block: separate raw images from the file protocol

Jan Kiszka (1):
block: Release allocated options after bdrv_open

Kevin Wolf (10):
block: Split bdrv_open
block: Avoid forward declaration of bdrv_open_common
block: Open the underlying image file in generic code
block: bdrv_has_zero_init
vmdk: Fix COW
vmdk: Clean up backing file handling
vmdk: Convert to bdrv_open
qcow2: Remove abort on free_clusters failure
block: Add wr_highest_sector blockstat qemu-img rebase: Fix output image corruption

Stefan Hajnoczi (6):
block: Set backing_hd to NULL after deleting it
qcow2: Avoid shadowing variable in alloc_clusters_noref()
raw-posix: Use pread/pwrite instead of lseek+read/write
block: Cache total_sectors to reduce bdrv_getlength calls
qemu-img: Add 'resize' command to grow/shrink disk images
qcow2: Implement bdrv_truncate() for growing images

  Makefile.objs          |    2 +-
  block.c                |  384 ++++++++++++++++++++++++++++++++++--------------
  block.h                |    2 +
  block/blkdebug.c       |   17 +--
  block/bochs.c          |    2 +-
  block/cloop.c          |    2 +-
  block/cow.c            |    2 +-
  block/curl.c           |   10 +-
  block/dmg.c            |    2 +-
  block/nbd.c            |    2 +-
  block/parallels.c      |    2 +-
  block/qcow.c           |   67 ++++-----
  block/qcow2-cluster.c  |   64 ++++----
  block/qcow2-refcount.c |   86 ++++++------
  block/qcow2-snapshot.c |   22 ++--
  block/qcow2.c          |  110 +++++++++-----
  block/qcow2.h          |    8 +-
  block/raw-posix.c      |   62 +++------
  block/raw-win32.c      |   16 +-
  block/raw.c            |  144 ++++++++++++++++++
  block/vdi.c            |   29 +---
  block/vmdk.c           |  140 +++++-------------
  block/vpc.c            |   32 ++---
  block/vvfat.c          |    2 +-
  block_int.h            |    6 +-
  qemu-img-cmds.hx       |    6 +
  qemu-img.c             |  104 +++++++++++++-
  qemu-img.texi          |   12 ++
  28 files changed, 843 insertions(+), 494 deletions(-)

create mode 100644 block/raw.c