[5/5] block/parallels: add backing support to readv/writev

Message ID 20180112090122.1702-6-klim.kireev@virtuozzo.com
State New
Headers show
Series
  • preparation for Parallels Disk xml driver
Related show

Commit Message

Klim Kireev Jan. 12, 2018, 9:01 a.m.
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>

Since parallels format supports backing files, refine
readv/writev (allocate_clusters) to redirect read/write requests
to a backing file (if cluster is not available in the current bs).

Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 6 deletions(-)

Patch

diff --git a/block/parallels.c b/block/parallels.c
index 7a8e8b05a9..d3802085e3 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -142,6 +142,7 @@  static int64_t block_status(BDRVParallelsState *s, int64_t sector_num,
 static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
                                  int nb_sectors, int *pnum)
 {
+    int ret;
     BDRVParallelsState *s = bs->opaque;
     int64_t pos, space, idx, to_allocate, i, len;
 
@@ -170,7 +171,6 @@  static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
         return len;
     }
     if (s->data_end + space > (len >> BDRV_SECTOR_BITS)) {
-        int ret;
         space += s->prealloc_size;
         if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
             ret = bdrv_pwrite_zeroes(bs->file,
@@ -186,6 +186,37 @@  static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
         }
     }
 
+    /* Try to read from backing to fill empty clusters
+     * FIXME: 1. previous write_zeroes may be redundant
+     *        2. most of data we read from backing will be rewritten by
+     *           parallels_co_writev. On aligned-to-cluster write we do not need
+     *           this read at all.
+     *        3. it would be good to combine write of data from backing and new
+     *           data into one write call */
+    if (bs->backing) {
+        int64_t nb_cow_sectors = to_allocate * s->tracks;
+        int64_t nb_cow_bytes = nb_cow_sectors << BDRV_SECTOR_BITS;
+        QEMUIOVector qiov;
+        struct iovec iov = {
+            .iov_len = nb_cow_bytes,
+            .iov_base = qemu_blockalign(bs, nb_cow_bytes)
+        };
+        qemu_iovec_init_external(&qiov, &iov, 1);
+
+        ret = bdrv_co_readv(bs->backing, idx * s->tracks, nb_cow_sectors,
+                            &qiov);
+        if (ret < 0) {
+            qemu_vfree(iov.iov_base);
+            return ret;
+        }
+
+        ret = bdrv_co_writev(bs->file, s->data_end, nb_cow_sectors, &qiov);
+        qemu_vfree(iov.iov_base);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
     for (i = 0; i < to_allocate; i++) {
         s->bat_bitmap[idx + i] = cpu_to_le32(s->data_end / s->off_multiplier);
         s->data_end += s->tracks;
@@ -309,12 +340,19 @@  static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
 
         nbytes = n << BDRV_SECTOR_BITS;
 
+        qemu_iovec_reset(&hd_qiov);
+        qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
+
         if (position < 0) {
-            qemu_iovec_memset(qiov, bytes_done, 0, nbytes);
+            if (bs->backing) {
+                ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
+                if (ret < 0) {
+                    break;
+                }
+            } else {
+                qemu_iovec_memset(&hd_qiov, 0, 0, nbytes);
+            }
         } else {
-            qemu_iovec_reset(&hd_qiov);
-            qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
-
             ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
             if (ret < 0) {
                 break;
@@ -748,7 +786,7 @@  static BlockDriver bdrv_parallels = {
     .bdrv_co_flush_to_os      = parallels_co_flush_to_os,
     .bdrv_co_readv  = parallels_co_readv,
     .bdrv_co_writev = parallels_co_writev,
-
+    .supports_backing = true,
     .bdrv_create    = parallels_create,
     .bdrv_check     = parallels_check,
     .create_opts    = &parallels_create_opts,