All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance
@ 2015-03-10  8:50 Denis V. Lunev
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 01/27] iotests, parallels: quote TEST_IMG in 076 test to be path-safe Denis V. Lunev
                   ` (26 more replies)
  0 siblings, 27 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:50 UTC (permalink / raw)
  Cc: Kevin Wolf, Roman Kagan, Jeff Cody, qemu-devel, Stefan Hajnoczi,
	Denis V. Lunev

This patchset provides an ability to create of/write to Parallels
images and some testing of the new code. Reading and writings are
optimized out and I expect the same or slightly better performance
as qcow2.

This patchset consists of not problematic part of the previous
patchset aka
   [PATCH v4 0/16] parallels format support improvements
and new write/create code but it does not contradict questionable code
with XML handling there.

Changes from v2:
- read performance is almost doubled (up to 360 Mb/sec), write performance
  is improved by 15-20%
- bat caching approach changed completely. bat_bitmap now contains the data
  in on-disk format, which allows to use this data for metadata cache
- incorrect close detection code is added (inuse field in the header)
- very basic check consistency code added

Changes from v1:
- patches 13-19 added, which boosts performance from 800 KiB/sec to
  near native performance

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>

P.S. This is definitely not for 2.3...

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 01/27] iotests, parallels: quote TEST_IMG in 076 test to be path-safe
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
@ 2015-03-10  8:50 ` Denis V. Lunev
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 02/27] block/parallels: rename parallels_header to ParallelsHeader Denis V. Lunev
                   ` (25 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:50 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

suggested by Jeff Cody

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/076 | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076
index ed2be35..0139976 100755
--- a/tests/qemu-iotests/076
+++ b/tests/qemu-iotests/076
@@ -49,31 +49,31 @@ nb_sectors_offset=$((0x24))
 echo
 echo "== Read from a valid v1 image =="
 _use_sample_img parallels-v1.bz2
-{ $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
 
 echo
 echo "== Negative catalog size =="
 _use_sample_img parallels-v1.bz2
 poke_file "$TEST_IMG" "$catalog_entries_offset" "\xff\xff\xff\xff"
-{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "read 0 512" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
 
 echo
 echo "== Overflow in catalog allocation =="
 _use_sample_img parallels-v1.bz2
 poke_file "$TEST_IMG" "$nb_sectors_offset" "\xff\xff\xff\xff"
 poke_file "$TEST_IMG" "$catalog_entries_offset" "\x01\x00\x00\x40"
-{ $QEMU_IO -c "read 64M 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "read 64M 64M" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
 
 echo
 echo "== Zero sectors per track =="
 _use_sample_img parallels-v1.bz2
 poke_file "$TEST_IMG" "$tracks_offset" "\x00\x00\x00\x00"
-{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "read 0 512" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
 
 echo
 echo "== Read from a valid v2 image =="
 _use_sample_img parallels-v2.bz2
-{ $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
 
 # success, all done
 echo "*** done"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 02/27] block/parallels: rename parallels_header to ParallelsHeader
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 01/27] iotests, parallels: quote TEST_IMG in 076 test to be path-safe Denis V. Lunev
@ 2015-03-10  8:50 ` Denis V. Lunev
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read Denis V. Lunev
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:50 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

this follows QEMU coding convention

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 4f9cd8d..dca0df6 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -35,7 +35,7 @@
 #define HEADER_SIZE 64
 
 // always little-endian
-struct parallels_header {
+typedef struct ParallelsHeader {
     char magic[16]; // "WithoutFreeSpace"
     uint32_t version;
     uint32_t heads;
@@ -46,7 +46,7 @@ struct parallels_header {
     uint32_t inuse;
     uint32_t data_off;
     char padding[12];
-} QEMU_PACKED;
+} QEMU_PACKED ParallelsHeader;
 
 typedef struct BDRVParallelsState {
     CoMutex lock;
@@ -61,7 +61,7 @@ typedef struct BDRVParallelsState {
 
 static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
-    const struct parallels_header *ph = (const void *)buf;
+    const ParallelsHeader *ph = (const void *)buf;
 
     if (buf_size < HEADER_SIZE)
         return 0;
@@ -79,7 +79,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
 {
     BDRVParallelsState *s = bs->opaque;
     int i;
-    struct parallels_header ph;
+    ParallelsHeader ph;
     int ret;
 
     bs->read_only = 1; // no write support yet
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 01/27] iotests, parallels: quote TEST_IMG in 076 test to be path-safe Denis V. Lunev
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 02/27] block/parallels: rename parallels_header to ParallelsHeader Denis V. Lunev
@ 2015-03-10  8:50 ` Denis V. Lunev
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 04/27] block/parallels: read up to cluster end in one go Denis V. Lunev
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:50 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

From: Roman Kagan <rkagan@parallels.com>

Switch the .bdrv_read method implementation from using bdrv_pread() to
bdrv_read() on the underlying file, since the latter is subject to i/o
throttling while the former is not.

Besides, since bdrv_read() operates in sectors rather than bytes, adjust
the helper functions to do so too.

Signed-off-by: Roman Kagan <rkagan@parallels.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index dca0df6..baefd3e 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -146,9 +146,8 @@ fail:
     return ret;
 }
 
-static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
+static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
 {
-    BDRVParallelsState *s = bs->opaque;
     uint32_t index, offset;
 
     index = sector_num / s->tracks;
@@ -157,24 +156,27 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
     /* not allocated */
     if ((index >= s->catalog_size) || (s->catalog_bitmap[index] == 0))
         return -1;
-    return
-        ((uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset) * 512;
+    return (uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset;
 }
 
 static int parallels_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
+    BDRVParallelsState *s = bs->opaque;
+
     while (nb_sectors > 0) {
-        int64_t position = seek_to_sector(bs, sector_num);
+        int64_t position = seek_to_sector(s, sector_num);
         if (position >= 0) {
-            if (bdrv_pread(bs->file, position, buf, 512) != 512)
-                return -1;
+            int ret = bdrv_read(bs->file, position, buf, 1);
+            if (ret < 0) {
+                return ret;
+            }
         } else {
-            memset(buf, 0, 512);
+            memset(buf, 0, BDRV_SECTOR_SIZE);
         }
         nb_sectors--;
         sector_num++;
-        buf += 512;
+        buf += BDRV_SECTOR_SIZE;
     }
     return 0;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 04/27] block/parallels: read up to cluster end in one go
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (2 preceding siblings ...)
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read Denis V. Lunev
@ 2015-03-10  8:50 ` Denis V. Lunev
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 05/27] block/parallels: add get_block_status Denis V. Lunev
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:50 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

From: Roman Kagan <rkagan@parallels.com>

Teach parallels_read() to do reads in coarser granularity than just a
single sector: if requested, read up to the cluster end in one go.

Signed-off-by: Roman Kagan <rkagan@parallels.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index baefd3e..8770c82 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -159,6 +159,13 @@ static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
     return (uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset;
 }
 
+static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
+        int nb_sectors)
+{
+    int ret = s->tracks - sector_num % s->tracks;
+    return MIN(nb_sectors, ret);
+}
+
 static int parallels_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
@@ -166,17 +173,18 @@ static int parallels_read(BlockDriverState *bs, int64_t sector_num,
 
     while (nb_sectors > 0) {
         int64_t position = seek_to_sector(s, sector_num);
+        int n = cluster_remainder(s, sector_num, nb_sectors);
         if (position >= 0) {
-            int ret = bdrv_read(bs->file, position, buf, 1);
+            int ret = bdrv_read(bs->file, position, buf, n);
             if (ret < 0) {
                 return ret;
             }
         } else {
-            memset(buf, 0, BDRV_SECTOR_SIZE);
+            memset(buf, 0, n << BDRV_SECTOR_BITS);
         }
-        nb_sectors--;
-        sector_num++;
-        buf += BDRV_SECTOR_SIZE;
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n << BDRV_SECTOR_BITS;
     }
     return 0;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 05/27] block/parallels: add get_block_status
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (3 preceding siblings ...)
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 04/27] block/parallels: read up to cluster end in one go Denis V. Lunev
@ 2015-03-10  8:50 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 06/27] block/parallels: provide _co_readv routine for parallels format driver Denis V. Lunev
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:50 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

From: Roman Kagan <rkagan@parallels.com>

Implement VFS method for get_block_status to Parallels format driver.

Signed-off-by: Roman Kagan <rkagan@parallels.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/block/parallels.c b/block/parallels.c
index 8770c82..b469984 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -166,6 +166,26 @@ static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
     return MIN(nb_sectors, ret);
 }
 
+static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors, int *pnum)
+{
+    BDRVParallelsState *s = bs->opaque;
+    int64_t offset;
+
+    qemu_co_mutex_lock(&s->lock);
+    offset = seek_to_sector(s, sector_num);
+    qemu_co_mutex_unlock(&s->lock);
+
+    *pnum = cluster_remainder(s, sector_num, nb_sectors);
+
+    if (offset < 0) {
+        return 0;
+    }
+
+    return (offset << BDRV_SECTOR_BITS) |
+        BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
+}
+
 static int parallels_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
@@ -213,6 +233,7 @@ static BlockDriver bdrv_parallels = {
     .bdrv_open		= parallels_open,
     .bdrv_read          = parallels_co_read,
     .bdrv_close		= parallels_close,
+    .bdrv_co_get_block_status = parallels_co_get_block_status,
 };
 
 static void bdrv_parallels_init(void)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 06/27] block/parallels: provide _co_readv routine for parallels format driver
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (4 preceding siblings ...)
  2015-03-10  8:50 ` [Qemu-devel] [PATCH 05/27] block/parallels: add get_block_status Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 07/27] block/parallels: replace magic constants 4, 64 with proper sizeofs Denis V. Lunev
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

Main approach is taken from qcow2_co_readv.

The patch drops coroutine lock for the duration of IO operation and
peforms normal scatter-gather IO using standard QEMU backend.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 46 +++++++++++++++++++++++++++-------------------
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index b469984..64b169b 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -186,37 +186,45 @@ static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
         BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
 }
 
-static int parallels_read(BlockDriverState *bs, int64_t sector_num,
-                    uint8_t *buf, int nb_sectors)
+static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
 {
     BDRVParallelsState *s = bs->opaque;
+    uint64_t bytes_done = 0;
+    QEMUIOVector hd_qiov;
+    int ret = 0;
 
+    qemu_iovec_init(&hd_qiov, qiov->niov);
+
+    qemu_co_mutex_lock(&s->lock);
     while (nb_sectors > 0) {
         int64_t position = seek_to_sector(s, sector_num);
         int n = cluster_remainder(s, sector_num, nb_sectors);
-        if (position >= 0) {
-            int ret = bdrv_read(bs->file, position, buf, n);
+        int nbytes = n << BDRV_SECTOR_BITS;
+
+        if (position < 0) {
+            qemu_iovec_memset(qiov, bytes_done, 0, nbytes);
+        } else {
+            qemu_iovec_reset(&hd_qiov);
+            qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
+
+            qemu_co_mutex_unlock(&s->lock);
+            ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
+            qemu_co_mutex_lock(&s->lock);
+
             if (ret < 0) {
-                return ret;
+                goto fail;
             }
-        } else {
-            memset(buf, 0, n << BDRV_SECTOR_BITS);
         }
+
         nb_sectors -= n;
         sector_num += n;
-        buf += n << BDRV_SECTOR_BITS;
+        bytes_done += nbytes;
     }
-    return 0;
-}
-
-static coroutine_fn int parallels_co_read(BlockDriverState *bs, int64_t sector_num,
-                                          uint8_t *buf, int nb_sectors)
-{
-    int ret;
-    BDRVParallelsState *s = bs->opaque;
-    qemu_co_mutex_lock(&s->lock);
-    ret = parallels_read(bs, sector_num, buf, nb_sectors);
     qemu_co_mutex_unlock(&s->lock);
+
+fail:
+    qemu_iovec_destroy(&hd_qiov);
     return ret;
 }
 
@@ -231,9 +239,9 @@ static BlockDriver bdrv_parallels = {
     .instance_size	= sizeof(BDRVParallelsState),
     .bdrv_probe		= parallels_probe,
     .bdrv_open		= parallels_open,
-    .bdrv_read          = parallels_co_read,
     .bdrv_close		= parallels_close,
     .bdrv_co_get_block_status = parallels_co_get_block_status,
+    .bdrv_co_readv  = parallels_co_readv,
 };
 
 static void bdrv_parallels_init(void)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 07/27] block/parallels: replace magic constants 4, 64 with proper sizeofs
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (5 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 06/27] block/parallels: provide _co_readv routine for parallels format driver Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 08/27] block/parallels: _co_writev callback for Parallels format Denis V. Lunev
                   ` (19 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

simple purification..

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 64b169b..306f2e3 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -32,7 +32,6 @@
 #define HEADER_MAGIC "WithoutFreeSpace"
 #define HEADER_MAGIC2 "WithouFreSpacExt"
 #define HEADER_VERSION 2
-#define HEADER_SIZE 64
 
 // always little-endian
 typedef struct ParallelsHeader {
@@ -63,7 +62,7 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
 {
     const ParallelsHeader *ph = (const void *)buf;
 
-    if (buf_size < HEADER_SIZE)
+    if (buf_size < sizeof(ParallelsHeader))
         return 0;
 
     if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
@@ -116,7 +115,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     s->catalog_size = le32_to_cpu(ph.catalog_entries);
-    if (s->catalog_size > INT_MAX / 4) {
+    if (s->catalog_size > INT_MAX / sizeof(uint32_t)) {
         error_setg(errp, "Catalog too large");
         ret = -EFBIG;
         goto fail;
@@ -127,7 +126,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         goto fail;
     }
 
-    ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
+    ret = bdrv_pread(bs->file, sizeof(ParallelsHeader),
+                     s->catalog_bitmap, s->catalog_size * sizeof(uint32_t));
     if (ret < 0) {
         goto fail;
     }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 08/27] block/parallels: _co_writev callback for Parallels format
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (6 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 07/27] block/parallels: replace magic constants 4, 64 with proper sizeofs Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 09/27] iotests, parallels: test for write into Parallels image Denis V. Lunev
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

Support write on Parallels images. The code is almost the same as one
in the previous patch implemented scatter-gather IO for read.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 75 insertions(+), 2 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 306f2e3..61d7da7 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -81,8 +81,6 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     ParallelsHeader ph;
     int ret;
 
-    bs->read_only = 1; // no write support yet
-
     ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
     if (ret < 0) {
         goto fail;
@@ -166,6 +164,37 @@ static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
     return MIN(nb_sectors, ret);
 }
 
+static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
+{
+    BDRVParallelsState *s = bs->opaque;
+    uint32_t idx, offset, tmp;
+    int64_t pos;
+    int ret;
+
+    idx = sector_num / s->tracks;
+    offset = sector_num % s->tracks;
+
+    if (idx >= s->catalog_size) {
+        return -EINVAL;
+    }
+    if (s->catalog_bitmap[idx] != 0) {
+        return (uint64_t)s->catalog_bitmap[idx] * s->off_multiplier + offset;
+    }
+
+    pos = bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS;
+    bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS);
+    s->catalog_bitmap[idx] = pos / s->off_multiplier;
+
+    tmp = cpu_to_le32(s->catalog_bitmap[idx]);
+
+    ret = bdrv_pwrite_sync(bs->file,
+            sizeof(ParallelsHeader) + idx * sizeof(tmp), &tmp, sizeof(tmp));
+    if (ret < 0) {
+        return ret;
+    }
+    return (uint64_t)s->catalog_bitmap[idx] * s->off_multiplier + offset;
+}
+
 static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, int *pnum)
 {
@@ -186,6 +215,49 @@ static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
         BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
 }
 
+static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+{
+    BDRVParallelsState *s = bs->opaque;
+    uint64_t bytes_done = 0;
+    QEMUIOVector hd_qiov;
+    int ret = 0;
+
+    qemu_iovec_init(&hd_qiov, qiov->niov);
+
+    qemu_co_mutex_lock(&s->lock);
+    while (nb_sectors > 0) {
+        int64_t position = allocate_cluster(bs, sector_num);
+        int n = cluster_remainder(s, sector_num, nb_sectors);
+        int nbytes = n << BDRV_SECTOR_BITS;
+
+        if (position < 0) {
+            ret = (int)position;
+            break;
+        }
+
+        qemu_iovec_reset(&hd_qiov);
+        qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
+
+        qemu_co_mutex_unlock(&s->lock);
+        ret = bdrv_co_writev(bs->file, position, n, &hd_qiov);
+        qemu_co_mutex_lock(&s->lock);
+
+        if (ret < 0) {
+            goto fail;
+        }
+
+        nb_sectors -= n;
+        sector_num += n;
+        bytes_done += nbytes;
+    }
+    qemu_co_mutex_unlock(&s->lock);
+
+fail:
+    qemu_iovec_destroy(&hd_qiov);
+    return ret;
+}
+
 static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
 {
@@ -242,6 +314,7 @@ static BlockDriver bdrv_parallels = {
     .bdrv_close		= parallels_close,
     .bdrv_co_get_block_status = parallels_co_get_block_status,
     .bdrv_co_readv  = parallels_co_readv,
+    .bdrv_co_writev = parallels_co_writev,
 };
 
 static void bdrv_parallels_init(void)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 09/27] iotests, parallels: test for write into Parallels image
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (7 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 08/27] block/parallels: _co_writev callback for Parallels format Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 10/27] block/parallels: support parallels image creation Denis V. Lunev
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/076     |  5 +++++
 tests/qemu-iotests/076.out | 10 ++++++++++
 2 files changed, 15 insertions(+)

diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076
index 0139976..c9b55a9 100755
--- a/tests/qemu-iotests/076
+++ b/tests/qemu-iotests/076
@@ -74,6 +74,11 @@ echo
 echo "== Read from a valid v2 image =="
 _use_sample_img parallels-v2.bz2
 { $QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "write -P 0x21 1024k 1k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "write -P 0x22 1025k 1k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "read -P 0x21 1024k 1k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "read -P 0x22 1025k 1k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+{ $QEMU_IO -c "read -P 0 1026k 62k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
 
 # success, all done
 echo "*** done"
diff --git a/tests/qemu-iotests/076.out b/tests/qemu-iotests/076.out
index 32ade08..b0000ae 100644
--- a/tests/qemu-iotests/076.out
+++ b/tests/qemu-iotests/076.out
@@ -19,4 +19,14 @@ no file open, try 'help open'
 == Read from a valid v2 image ==
 read 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1024/1024 bytes at offset 1048576
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1024/1024 bytes at offset 1049600
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 1024/1024 bytes at offset 1048576
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 1024/1024 bytes at offset 1049600
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 63488/63488 bytes at offset 1050624
+62 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 *** done
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 10/27] block/parallels: support parallels image creation
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (8 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 09/27] iotests, parallels: test for write into Parallels image Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 11/27] iotests, parallels: test for newly created parallels image via qemu-img Denis V. Lunev
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

Do not even care to create WithoutFreeSpace image, it is obsolete.
Always create WithouFreSpacExt one.

The code also does not spend a lot of efforts to fill cylinders and
heads fields, they are not used actually in a real life neither in
QEMU nor in Parallels products.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviwed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/block/parallels.c b/block/parallels.c
index 61d7da7..28338ec 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -33,6 +33,9 @@
 #define HEADER_MAGIC2 "WithouFreSpacExt"
 #define HEADER_VERSION 2
 
+#define DEFAULT_CLUSTER_SIZE 1048576        /* 1 MiB */
+
+
 // always little-endian
 typedef struct ParallelsHeader {
     char magic[16]; // "WithoutFreeSpace"
@@ -300,12 +303,103 @@ fail:
     return ret;
 }
 
+static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
+{
+    int64_t total_size, cl_size;
+    uint8_t tmp[BDRV_SECTOR_SIZE];
+    Error *local_err = NULL;
+    BlockDriverState *file;
+    uint32_t cat_entries, cat_sectors;
+    ParallelsHeader header;
+    int ret;
+
+    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+                          BDRV_SECTOR_SIZE);
+    cl_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
+                          DEFAULT_CLUSTER_SIZE), BDRV_SECTOR_SIZE);
+
+    ret = bdrv_create_file(filename, opts, &local_err);
+    if (ret < 0) {
+        error_propagate(errp, local_err);
+        return ret;
+    }
+
+    file = NULL;
+    ret = bdrv_open(&file, filename, NULL, NULL,
+                    BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
+    if (ret < 0) {
+        error_propagate(errp, local_err);
+        return ret;
+    }
+    ret = bdrv_truncate(file, 0);
+    if (ret < 0) {
+        goto exit;
+    }
+
+    cat_entries = DIV_ROUND_UP(total_size, cl_size);
+    cat_sectors = DIV_ROUND_UP(cat_entries * sizeof(uint32_t) +
+                               sizeof(ParallelsHeader), cl_size);
+    cat_sectors = (cat_sectors *  cl_size) >> BDRV_SECTOR_BITS;
+
+    memset(&header, 0, sizeof(header));
+    memcpy(header.magic, HEADER_MAGIC2, sizeof(header.magic));
+    header.version = cpu_to_le32(HEADER_VERSION);
+    /* don't care much about geometry, it is not used on image level */
+    header.heads = cpu_to_le32(16);
+    header.cylinders = cpu_to_le32(total_size / BDRV_SECTOR_SIZE / 16 / 32);
+    header.tracks = cpu_to_le32(cl_size >> BDRV_SECTOR_BITS);
+    header.catalog_entries = cpu_to_le32(cat_entries);
+    header.nb_sectors = cpu_to_le64(DIV_ROUND_UP(total_size, BDRV_SECTOR_SIZE));
+    header.data_off = cpu_to_le32(cat_sectors);
+
+    /* write all the data */
+    memset(tmp, 0, sizeof(tmp));
+    memcpy(tmp, &header, sizeof(header));
+
+    ret = bdrv_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE);
+    if (ret < 0) {
+        goto exit;
+    }
+    ret = bdrv_write_zeroes(file, 1, cat_sectors - 1, 0);
+    if (ret < 0) {
+        goto exit;
+    }
+    ret = 0;
+
+done:
+    bdrv_unref(file);
+    return ret;
+
+exit:
+    error_setg_errno(errp, -ret, "Failed to create Parallels image");
+    goto done;
+}
+
 static void parallels_close(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
     g_free(s->catalog_bitmap);
 }
 
+static QemuOptsList parallels_create_opts = {
+    .name = "parallels-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(parallels_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Virtual disk size",
+        },
+        {
+            .name = BLOCK_OPT_CLUSTER_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Parallels image cluster size",
+            .def_value_str = stringify(DEFAULT_CLUSTER_SIZE),
+        },
+        { /* end of list */ }
+    }
+};
+
 static BlockDriver bdrv_parallels = {
     .format_name	= "parallels",
     .instance_size	= sizeof(BDRVParallelsState),
@@ -315,6 +409,9 @@ static BlockDriver bdrv_parallels = {
     .bdrv_co_get_block_status = parallels_co_get_block_status,
     .bdrv_co_readv  = parallels_co_readv,
     .bdrv_co_writev = parallels_co_writev,
+
+    .bdrv_create    = parallels_create,
+    .create_opts    = &parallels_create_opts,
 };
 
 static void bdrv_parallels_init(void)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 11/27] iotests, parallels: test for newly created parallels image via qemu-img
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (9 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 10/27] block/parallels: support parallels image creation Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 12/27] parallels: change copyright information in the image header Denis V. Lunev
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviwed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/115     | 68 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/115.out | 24 ++++++++++++++++
 tests/qemu-iotests/group   |  1 +
 3 files changed, 93 insertions(+)
 create mode 100755 tests/qemu-iotests/115
 create mode 100644 tests/qemu-iotests/115.out

diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115
new file mode 100755
index 0000000..f45afa7
--- /dev/null
+++ b/tests/qemu-iotests/115
@@ -0,0 +1,68 @@
+#!/bin/bash
+#
+# parallels format validation tests (created by QEMU)
+#
+# Copyright (C) 2014 Denis V. Lunev <den@openvz.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=den@openvz.org
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+    _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt parallels
+_supported_proto file
+_supported_os Linux
+
+size=64M
+CLUSTER_SIZE=64k
+IMGFMT=parallels
+_make_test_img $size
+
+echo == read empty image ==
+{ $QEMU_IO -c "read -P 0 32k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == write more than 1 block in a row ==
+{ $QEMU_IO -c "write -P 0x11 32k 128k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == read less than block ==
+{ $QEMU_IO -c "read -P 0x11 32k 32k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == read exactly 1 block ==
+{ $QEMU_IO -c "read -P 0x11 64k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == read more than 1 block ==
+{ $QEMU_IO -c "read -P 0x11 32k 128k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == check that there is no trash after written ==
+{ $QEMU_IO -c "read -P 0 160k 32k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == check that there is no trash before written ==
+{ $QEMU_IO -c "read -P 0 0 32k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/115.out b/tests/qemu-iotests/115.out
new file mode 100644
index 0000000..6a73104
--- /dev/null
+++ b/tests/qemu-iotests/115.out
@@ -0,0 +1,24 @@
+QA output created by 115
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+== read empty image ==
+read 65536/65536 bytes at offset 32768
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== write more than 1 block in a row ==
+wrote 131072/131072 bytes at offset 32768
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== read less than block ==
+read 32768/32768 bytes at offset 32768
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== read exactly 1 block ==
+read 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== read more than 1 block ==
+read 131072/131072 bytes at offset 32768
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== check that there is no trash after written ==
+read 32768/32768 bytes at offset 163840
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== check that there is no trash before written ==
+read 32768/32768 bytes at offset 0
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 0d3b95c..3794af7 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -118,5 +118,6 @@
 111 rw auto quick
 113 rw auto quick
 114 rw auto quick
+115 rw auto quick
 116 rw auto quick
 123 rw auto quick
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 12/27] parallels: change copyright information in the image header
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (10 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 11/27] iotests, parallels: test for newly created parallels image via qemu-img Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 13/27] block/parallels: rename catalog_ names to bat_ Denis V. Lunev
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviwed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/block/parallels.c b/block/parallels.c
index 28338ec..7ef3136 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -2,8 +2,12 @@
  * Block driver for Parallels disk image format
  *
  * Copyright (c) 2007 Alex Beregszaszi
+ * Copyright (c) 2014 Denis V. Lunev <den@openvz.org>
  *
- * This code is based on comparing different disk images created by Parallels.
+ * This code was originally based on comparing different disk images created
+ * by Parallels. Currently it is based on opened OpenVZ sources
+ * available at
+ *     http://git.openvz.org/?p=ploop;a=summary
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 13/27] block/parallels: rename catalog_ names to bat_
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (11 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 12/27] parallels: change copyright information in the image header Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 14/27] block/parallels: create bat2sect helper Denis V. Lunev
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi

BAT means 'block allocation table'. Thus this name is clean and shorter
on writing.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 54 +++++++++++++++++++++++++++---------------------------
 1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 7ef3136..3d5f509 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -47,7 +47,7 @@ typedef struct ParallelsHeader {
     uint32_t heads;
     uint32_t cylinders;
     uint32_t tracks;
-    uint32_t catalog_entries;
+    uint32_t bat_entries;
     uint64_t nb_sectors;
     uint32_t inuse;
     uint32_t data_off;
@@ -57,8 +57,8 @@ typedef struct ParallelsHeader {
 typedef struct BDRVParallelsState {
     CoMutex lock;
 
-    uint32_t *catalog_bitmap;
-    unsigned int catalog_size;
+    uint32_t *bat_bitmap;
+    unsigned int bat_size;
 
     unsigned int tracks;
 
@@ -119,26 +119,26 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         goto fail;
     }
 
-    s->catalog_size = le32_to_cpu(ph.catalog_entries);
-    if (s->catalog_size > INT_MAX / sizeof(uint32_t)) {
+    s->bat_size = le32_to_cpu(ph.bat_entries);
+    if (s->bat_size > INT_MAX / sizeof(uint32_t)) {
         error_setg(errp, "Catalog too large");
         ret = -EFBIG;
         goto fail;
     }
-    s->catalog_bitmap = g_try_new(uint32_t, s->catalog_size);
-    if (s->catalog_size && s->catalog_bitmap == NULL) {
+    s->bat_bitmap = g_try_new(uint32_t, s->bat_size);
+    if (s->bat_size && s->bat_bitmap == NULL) {
         ret = -ENOMEM;
         goto fail;
     }
 
     ret = bdrv_pread(bs->file, sizeof(ParallelsHeader),
-                     s->catalog_bitmap, s->catalog_size * sizeof(uint32_t));
+                     s->bat_bitmap, s->bat_size * sizeof(uint32_t));
     if (ret < 0) {
         goto fail;
     }
 
-    for (i = 0; i < s->catalog_size; i++)
-        le32_to_cpus(&s->catalog_bitmap[i]);
+    for (i = 0; i < s->bat_size; i++)
+        le32_to_cpus(&s->bat_bitmap[i]);
 
     qemu_co_mutex_init(&s->lock);
     return 0;
@@ -147,7 +147,7 @@ fail_format:
     error_setg(errp, "Image not in Parallels format");
     ret = -EINVAL;
 fail:
-    g_free(s->catalog_bitmap);
+    g_free(s->bat_bitmap);
     return ret;
 }
 
@@ -159,9 +159,9 @@ static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
     offset = sector_num % s->tracks;
 
     /* not allocated */
-    if ((index >= s->catalog_size) || (s->catalog_bitmap[index] == 0))
+    if ((index >= s->bat_size) || (s->bat_bitmap[index] == 0))
         return -1;
-    return (uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset;
+    return (uint64_t)s->bat_bitmap[index] * s->off_multiplier + offset;
 }
 
 static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
@@ -181,25 +181,25 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
     idx = sector_num / s->tracks;
     offset = sector_num % s->tracks;
 
-    if (idx >= s->catalog_size) {
+    if (idx >= s->bat_size) {
         return -EINVAL;
     }
-    if (s->catalog_bitmap[idx] != 0) {
-        return (uint64_t)s->catalog_bitmap[idx] * s->off_multiplier + offset;
+    if (s->bat_bitmap[idx] != 0) {
+        return (uint64_t)s->bat_bitmap[idx] * s->off_multiplier + offset;
     }
 
     pos = bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS;
     bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS);
-    s->catalog_bitmap[idx] = pos / s->off_multiplier;
+    s->bat_bitmap[idx] = pos / s->off_multiplier;
 
-    tmp = cpu_to_le32(s->catalog_bitmap[idx]);
+    tmp = cpu_to_le32(s->bat_bitmap[idx]);
 
     ret = bdrv_pwrite_sync(bs->file,
             sizeof(ParallelsHeader) + idx * sizeof(tmp), &tmp, sizeof(tmp));
     if (ret < 0) {
         return ret;
     }
-    return (uint64_t)s->catalog_bitmap[idx] * s->off_multiplier + offset;
+    return (uint64_t)s->bat_bitmap[idx] * s->off_multiplier + offset;
 }
 
 static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
@@ -313,7 +313,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
     uint8_t tmp[BDRV_SECTOR_SIZE];
     Error *local_err = NULL;
     BlockDriverState *file;
-    uint32_t cat_entries, cat_sectors;
+    uint32_t bat_entries, bat_sectors;
     ParallelsHeader header;
     int ret;
 
@@ -340,10 +340,10 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
         goto exit;
     }
 
-    cat_entries = DIV_ROUND_UP(total_size, cl_size);
-    cat_sectors = DIV_ROUND_UP(cat_entries * sizeof(uint32_t) +
+    bat_entries = DIV_ROUND_UP(total_size, cl_size);
+    bat_sectors = DIV_ROUND_UP(bat_entries * sizeof(uint32_t) +
                                sizeof(ParallelsHeader), cl_size);
-    cat_sectors = (cat_sectors *  cl_size) >> BDRV_SECTOR_BITS;
+    bat_sectors = (bat_sectors *  cl_size) >> BDRV_SECTOR_BITS;
 
     memset(&header, 0, sizeof(header));
     memcpy(header.magic, HEADER_MAGIC2, sizeof(header.magic));
@@ -352,9 +352,9 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
     header.heads = cpu_to_le32(16);
     header.cylinders = cpu_to_le32(total_size / BDRV_SECTOR_SIZE / 16 / 32);
     header.tracks = cpu_to_le32(cl_size >> BDRV_SECTOR_BITS);
-    header.catalog_entries = cpu_to_le32(cat_entries);
+    header.bat_entries = cpu_to_le32(bat_entries);
     header.nb_sectors = cpu_to_le64(DIV_ROUND_UP(total_size, BDRV_SECTOR_SIZE));
-    header.data_off = cpu_to_le32(cat_sectors);
+    header.data_off = cpu_to_le32(bat_sectors);
 
     /* write all the data */
     memset(tmp, 0, sizeof(tmp));
@@ -364,7 +364,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
     if (ret < 0) {
         goto exit;
     }
-    ret = bdrv_write_zeroes(file, 1, cat_sectors - 1, 0);
+    ret = bdrv_write_zeroes(file, 1, bat_sectors - 1, 0);
     if (ret < 0) {
         goto exit;
     }
@@ -382,7 +382,7 @@ exit:
 static void parallels_close(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
-    g_free(s->catalog_bitmap);
+    g_free(s->bat_bitmap);
 }
 
 static QemuOptsList parallels_create_opts = {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 14/27] block/parallels: create bat2sect helper
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (12 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 13/27] block/parallels: rename catalog_ names to bat_ Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 12:14   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 15/27] block/parallels: keep BAT bitmap data in little endian in memory Denis V. Lunev
                   ` (12 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

deduplicate copy/paste arithmetcs

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 3d5f509..95e99cc 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -151,6 +151,12 @@ fail:
     return ret;
 }
 
+
+static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
+{
+    return (uint64_t)s->bat_bitmap[idx] * s->off_multiplier;
+}
+
 static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
 {
     uint32_t index, offset;
@@ -161,7 +167,7 @@ static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
     /* not allocated */
     if ((index >= s->bat_size) || (s->bat_bitmap[index] == 0))
         return -1;
-    return (uint64_t)s->bat_bitmap[index] * s->off_multiplier + offset;
+    return bat2sect(s, index) + offset;
 }
 
 static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
@@ -185,7 +191,7 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
         return -EINVAL;
     }
     if (s->bat_bitmap[idx] != 0) {
-        return (uint64_t)s->bat_bitmap[idx] * s->off_multiplier + offset;
+        return bat2sect(s, idx) + offset;
     }
 
     pos = bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS;
@@ -199,7 +205,7 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
     if (ret < 0) {
         return ret;
     }
-    return (uint64_t)s->bat_bitmap[idx] * s->off_multiplier + offset;
+    return bat2sect(s, idx) + offset;
 }
 
 static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 15/27] block/parallels: keep BAT bitmap data in little endian in memory
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (13 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 14/27] block/parallels: create bat2sect helper Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 12:16   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 16/27] block/parallels: read parallels image header and BAT into single buffer Denis V. Lunev
                   ` (11 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

This will allow to use this data as buffer to BAT update directly
without any intermediate buffers.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 95e99cc..a6d2dfd 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -84,7 +84,6 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
                           Error **errp)
 {
     BDRVParallelsState *s = bs->opaque;
-    int i;
     ParallelsHeader ph;
     int ret;
 
@@ -137,9 +136,6 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         goto fail;
     }
 
-    for (i = 0; i < s->bat_size; i++)
-        le32_to_cpus(&s->bat_bitmap[i]);
-
     qemu_co_mutex_init(&s->lock);
     return 0;
 
@@ -154,7 +150,7 @@ fail:
 
 static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
 {
-    return (uint64_t)s->bat_bitmap[idx] * s->off_multiplier;
+    return (uint64_t)le32_to_cpu(s->bat_bitmap[idx]) * s->off_multiplier;
 }
 
 static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
@@ -180,7 +176,7 @@ static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
 static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
 {
     BDRVParallelsState *s = bs->opaque;
-    uint32_t idx, offset, tmp;
+    uint32_t idx, offset;
     int64_t pos;
     int ret;
 
@@ -196,12 +192,11 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
 
     pos = bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS;
     bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS);
-    s->bat_bitmap[idx] = pos / s->off_multiplier;
-
-    tmp = cpu_to_le32(s->bat_bitmap[idx]);
 
+    s->bat_bitmap[idx] = cpu_to_le32(pos / s->off_multiplier);
     ret = bdrv_pwrite_sync(bs->file,
-            sizeof(ParallelsHeader) + idx * sizeof(tmp), &tmp, sizeof(tmp));
+            sizeof(ParallelsHeader) + idx * sizeof(s->bat_bitmap[idx]),
+            s->bat_bitmap + idx, sizeof(s->bat_bitmap[idx]));
     if (ret < 0) {
         return ret;
     }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 16/27] block/parallels: read parallels image header and BAT into single buffer
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (14 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 15/27] block/parallels: keep BAT bitmap data in little endian in memory Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 14:07   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 17/27] block/parallels: move parallels_open/probe to the very end of the file Denis V. Lunev
                   ` (10 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

This metadata cache would allow to properly batch BAT updates to disk
in next patches. These updates will be properly aligned to avoid
read-modify-write transactions on block level.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index a6d2dfd..ceed34d 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -57,6 +57,8 @@ typedef struct ParallelsHeader {
 typedef struct BDRVParallelsState {
     CoMutex lock;
 
+    ParallelsHeader *header;
+    uint32_t header_size;
     uint32_t *bat_bitmap;
     unsigned int bat_size;
 
@@ -85,7 +87,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
 {
     BDRVParallelsState *s = bs->opaque;
     ParallelsHeader ph;
-    int ret;
+    int ret, size;
 
     ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
     if (ret < 0) {
@@ -124,17 +126,25 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         ret = -EFBIG;
         goto fail;
     }
-    s->bat_bitmap = g_try_new(uint32_t, s->bat_size);
-    if (s->bat_size && s->bat_bitmap == NULL) {
+
+    size = sizeof(ParallelsHeader) + sizeof(uint32_t) * s->bat_size;
+    s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file));
+    s->header = qemu_try_blockalign(bs->file, s->header_size);
+    if (s->header == NULL) {
         ret = -ENOMEM;
         goto fail;
     }
+    if (le32_to_cpu(ph.data_off) < s->header_size) {
+        /* there is not enough unused space to fit to block align between BAT
+           and actual data. We can't avoid read-modify-write... */
+        s->header_size = size;
+    }
 
-    ret = bdrv_pread(bs->file, sizeof(ParallelsHeader),
-                     s->bat_bitmap, s->bat_size * sizeof(uint32_t));
+    ret = bdrv_pread(bs->file, 0, s->header, s->header_size);
     if (ret < 0) {
         goto fail;
     }
+    s->bat_bitmap = (uint32_t *)(s->header + 1);
 
     qemu_co_mutex_init(&s->lock);
     return 0;
@@ -143,7 +153,7 @@ fail_format:
     error_setg(errp, "Image not in Parallels format");
     ret = -EINVAL;
 fail:
-    g_free(s->bat_bitmap);
+    qemu_vfree(s->header);
     return ret;
 }
 
@@ -383,7 +393,7 @@ exit:
 static void parallels_close(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
-    g_free(s->bat_bitmap);
+    qemu_vfree(s->header);
 }
 
 static QemuOptsList parallels_create_opts = {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 17/27] block/parallels: move parallels_open/probe to the very end of the file
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (15 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 16/27] block/parallels: read parallels image header and BAT into single buffer Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 14:09   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 18/27] block/parallels: implement parallels_check method of block driver Denis V. Lunev
                   ` (9 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

This will help to avoid forward declarations for upcoming parallels_check

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 183 +++++++++++++++++++++++++++---------------------------
 1 file changed, 93 insertions(+), 90 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index ceed34d..65f6418 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -67,96 +67,6 @@ typedef struct BDRVParallelsState {
     unsigned int off_multiplier;
 } BDRVParallelsState;
 
-static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
-    const ParallelsHeader *ph = (const void *)buf;
-
-    if (buf_size < sizeof(ParallelsHeader))
-        return 0;
-
-    if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
-        !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
-        (le32_to_cpu(ph->version) == HEADER_VERSION))
-        return 100;
-
-    return 0;
-}
-
-static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
-                          Error **errp)
-{
-    BDRVParallelsState *s = bs->opaque;
-    ParallelsHeader ph;
-    int ret, size;
-
-    ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
-    if (ret < 0) {
-        goto fail;
-    }
-
-    bs->total_sectors = le64_to_cpu(ph.nb_sectors);
-
-    if (le32_to_cpu(ph.version) != HEADER_VERSION) {
-        goto fail_format;
-    }
-    if (!memcmp(ph.magic, HEADER_MAGIC, 16)) {
-        s->off_multiplier = 1;
-        bs->total_sectors = 0xffffffff & bs->total_sectors;
-    } else if (!memcmp(ph.magic, HEADER_MAGIC2, 16)) {
-        s->off_multiplier = le32_to_cpu(ph.tracks);
-    } else {
-        goto fail_format;
-    }
-
-    s->tracks = le32_to_cpu(ph.tracks);
-    if (s->tracks == 0) {
-        error_setg(errp, "Invalid image: Zero sectors per track");
-        ret = -EINVAL;
-        goto fail;
-    }
-    if (s->tracks > INT32_MAX/513) {
-        error_setg(errp, "Invalid image: Too big cluster");
-        ret = -EFBIG;
-        goto fail;
-    }
-
-    s->bat_size = le32_to_cpu(ph.bat_entries);
-    if (s->bat_size > INT_MAX / sizeof(uint32_t)) {
-        error_setg(errp, "Catalog too large");
-        ret = -EFBIG;
-        goto fail;
-    }
-
-    size = sizeof(ParallelsHeader) + sizeof(uint32_t) * s->bat_size;
-    s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file));
-    s->header = qemu_try_blockalign(bs->file, s->header_size);
-    if (s->header == NULL) {
-        ret = -ENOMEM;
-        goto fail;
-    }
-    if (le32_to_cpu(ph.data_off) < s->header_size) {
-        /* there is not enough unused space to fit to block align between BAT
-           and actual data. We can't avoid read-modify-write... */
-        s->header_size = size;
-    }
-
-    ret = bdrv_pread(bs->file, 0, s->header, s->header_size);
-    if (ret < 0) {
-        goto fail;
-    }
-    s->bat_bitmap = (uint32_t *)(s->header + 1);
-
-    qemu_co_mutex_init(&s->lock);
-    return 0;
-
-fail_format:
-    error_setg(errp, "Image not in Parallels format");
-    ret = -EINVAL;
-fail:
-    qemu_vfree(s->header);
-    return ret;
-}
-
 
 static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
 {
@@ -390,6 +300,99 @@ exit:
     goto done;
 }
 
+
+static int parallels_probe(const uint8_t *buf, int buf_size,
+                           const char *filename)
+{
+    const ParallelsHeader *ph = (const void *)buf;
+
+    if (buf_size < sizeof(ParallelsHeader))
+        return 0;
+
+    if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
+        !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
+        (le32_to_cpu(ph->version) == HEADER_VERSION))
+        return 100;
+
+    return 0;
+}
+
+static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
+                          Error **errp)
+{
+    BDRVParallelsState *s = bs->opaque;
+    ParallelsHeader ph;
+    int ret, size;
+
+    ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
+    if (ret < 0) {
+        goto fail;
+    }
+
+    bs->total_sectors = le64_to_cpu(ph.nb_sectors);
+
+    if (le32_to_cpu(ph.version) != HEADER_VERSION) {
+        goto fail_format;
+    }
+    if (!memcmp(ph.magic, HEADER_MAGIC, 16)) {
+        s->off_multiplier = 1;
+        bs->total_sectors = 0xffffffff & bs->total_sectors;
+    } else if (!memcmp(ph.magic, HEADER_MAGIC2, 16)) {
+        s->off_multiplier = le32_to_cpu(ph.tracks);
+    } else {
+        goto fail_format;
+    }
+
+    s->tracks = le32_to_cpu(ph.tracks);
+    if (s->tracks == 0) {
+        error_setg(errp, "Invalid image: Zero sectors per track");
+        ret = -EINVAL;
+        goto fail;
+    }
+    if (s->tracks > INT32_MAX/513) {
+        error_setg(errp, "Invalid image: Too big cluster");
+        ret = -EFBIG;
+        goto fail;
+    }
+
+    s->bat_size = le32_to_cpu(ph.bat_entries);
+    if (s->bat_size > INT_MAX / sizeof(uint32_t)) {
+        error_setg(errp, "Catalog too large");
+        ret = -EFBIG;
+        goto fail;
+    }
+
+    size = sizeof(ParallelsHeader) + sizeof(uint32_t) * s->bat_size;
+    s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file));
+    s->header = qemu_try_blockalign(bs->file, s->header_size);
+    if (s->header == NULL) {
+        ret = -ENOMEM;
+        goto fail;
+    }
+    if (le32_to_cpu(ph.data_off) < s->header_size) {
+        /* there is not enough unused space to fit to block align between BAT
+           and actual data. We can't avoid read-modify-write... */
+        s->header_size = size;
+    }
+
+    ret = bdrv_pread(bs->file, 0, s->header, s->header_size);
+    if (ret < 0) {
+        goto fail;
+    }
+    s->bat_bitmap = (uint32_t *)(s->header + 1);
+
+    qemu_co_mutex_init(&s->lock);
+    return 0;
+
+fail_format:
+    error_setg(errp, "Image not in Parallels format");
+    ret = -EINVAL;
+fail:
+    qemu_vfree(s->header);
+    return ret;
+}
+
+
 static void parallels_close(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 18/27] block/parallels: implement parallels_check method of block driver
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (16 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 17/27] block/parallels: move parallels_open/probe to the very end of the file Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 14:24   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 19/27] block/parallels: implement incorrect close detection Denis V. Lunev
                   ` (8 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

The check is very simple at the moment. It calculates necessary stats
and fix only the following errors:
- space leak at the end of the image. This would happens due to
  preallocation
- clusters outside the image are zeroed. Nothing else could be done here

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/block/parallels.c b/block/parallels.c
index 65f6418..e5b475e 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -228,6 +228,87 @@ fail:
     return ret;
 }
 
+
+static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
+                           BdrvCheckMode fix)
+{
+    BDRVParallelsState *s = bs->opaque;
+    int64_t size, prev_off, high_off;
+    int ret;
+    uint32_t i;
+    bool flush_bat = false;
+    int cluster_size = s->tracks << BDRV_SECTOR_BITS;
+
+    size = bdrv_getlength(bs->file);
+    if (size < 0) {
+        res->check_errors++;
+        return size;
+    }
+
+    res->bfi.total_clusters = s->bat_size;
+    res->bfi.compressed_clusters = 0; /* compression is not supported */
+
+    high_off = 0;
+    prev_off = 0;
+    for (i = 0; i < s->bat_size; i++) {
+        int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
+        if (off == 0)
+            continue;
+
+        /* cluster outside the image */
+        if (off > size) {
+            fprintf(stderr, "%s cluster %u is outside image\n",
+                    fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
+            res->corruptions++;
+            if (fix & BDRV_FIX_ERRORS) {
+                s->bat_bitmap[i] = 0;
+                res->corruptions_fixed++;
+                flush_bat = true;
+                continue;
+            }
+        }
+
+        res->bfi.allocated_clusters++;
+        if (off > high_off) {
+            high_off = off;
+        }
+
+        if (prev_off != 0 && (prev_off + cluster_size) != off) {
+            res->bfi.fragmented_clusters++;
+        }
+        prev_off = off;
+    }
+
+    if (flush_bat) {
+        ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
+        if (ret < 0) {
+            res->check_errors++;
+            return ret;
+        }
+    }
+
+    res->image_end_offset = high_off + cluster_size;
+    if (size > res->image_end_offset) {
+        int64_t count;
+        count = DIV_ROUND_UP(size - res->image_end_offset, cluster_size);
+        fprintf(stderr, "%s space leaked at the end of the image %" PRId64 "\n",
+                fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR",
+                size - res->image_end_offset);
+        res->leaks += count;
+        if (fix & BDRV_FIX_LEAKS) {
+            ret = bdrv_truncate(bs->file, res->image_end_offset);
+            if (ret < 0) {
+                res->check_errors++;
+                return ret;
+            }
+            res->leaks_fixed += count;
+        }
+    }
+
+    return 0;
+}
+
+
 static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
 {
     int64_t total_size, cl_size;
@@ -429,6 +510,7 @@ static BlockDriver bdrv_parallels = {
     .bdrv_co_writev = parallels_co_writev,
 
     .bdrv_create    = parallels_create,
+    .bdrv_check     = parallels_check,
     .create_opts    = &parallels_create_opts,
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 19/27] block/parallels: implement incorrect close detection
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (17 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 18/27] block/parallels: implement parallels_check method of block driver Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 14:38   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 20/27] iotests, parallels: check for incorrectly closed image in tests Denis V. Lunev
                   ` (7 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

The software driver must set inuse field in Parallels header to
0x746F6E59 when the image is opened in read-write mode. The presence of
this magic in the header on open forces image consistency check.

There is an unfortunate trick here. We can not check for inuse in
parallels_check as this will happen too late. It is possible to do
that for simple check, but during the fix this would always report
an error as the image was opened in BDRV_O_RDWR mode. Thus we save
the flag in BDRVParallelsState for this.

On the other hand, nothing should be done to clear inuse in
parallels_check. Generic close will do the job right.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/block/parallels.c b/block/parallels.c
index e5b475e..9933c49 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -36,6 +36,7 @@
 #define HEADER_MAGIC "WithoutFreeSpace"
 #define HEADER_MAGIC2 "WithouFreSpacExt"
 #define HEADER_VERSION 2
+#define HEADER_INUSE_MAGIC  (0x746F6E59)
 
 #define DEFAULT_CLUSTER_SIZE 1048576        /* 1 MiB */
 
@@ -59,6 +60,8 @@ typedef struct BDRVParallelsState {
 
     ParallelsHeader *header;
     uint32_t header_size;
+    bool header_unclean;
+
     uint32_t *bat_bitmap;
     unsigned int bat_size;
 
@@ -245,6 +248,17 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
         return size;
     }
 
+    if (s->header_unclean) {
+        fprintf(stderr, "%s image was not closed correctly\n",
+                fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
+        res->corruptions++;
+        if (fix & BDRV_FIX_ERRORS) {
+            /* parallels_close will do the job right */
+            res->corruptions_fixed++;
+            s->header_unclean = false;
+        }
+    }
+
     res->bfi.total_clusters = s->bat_size;
     res->bfi.compressed_clusters = 0; /* compression is not supported */
 
@@ -398,6 +412,17 @@ static int parallels_probe(const uint8_t *buf, int buf_size,
     return 0;
 }
 
+static int parallels_update_header(BlockDriverState *bs)
+{
+    BDRVParallelsState *s = bs->opaque;
+    unsigned size = MAX(bdrv_opt_mem_align(bs->file), sizeof(ParallelsHeader));
+
+    if (size > s->header_size) {
+        size = s->header_size;
+    }
+    return bdrv_pwrite_sync(bs->file, 0, s->header, size);
+}
+
 static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
                           Error **errp)
 {
@@ -462,6 +487,25 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     }
     s->bat_bitmap = (uint32_t *)(s->header + 1);
 
+    if (le32_to_cpu(ph.inuse) == HEADER_INUSE_MAGIC) {
+        /* Image was not closed correctly. The check is mandatory */
+        s->header_unclean = true;
+        if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_CHECK)) {
+            error_setg(errp, "parallels: Image was not closed correctly; "
+                       "cannot be opened read/write");
+            ret = -EACCES;
+            goto fail;
+        }
+    }
+
+    if (flags & BDRV_O_RDWR) {
+        s->header->inuse = cpu_to_le32(HEADER_INUSE_MAGIC);
+        ret = parallels_update_header(bs);
+        if (ret < 0) {
+            goto fail;
+        }
+    }
+
     qemu_co_mutex_init(&s->lock);
     return 0;
 
@@ -477,6 +521,12 @@ fail:
 static void parallels_close(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
+
+    if (bs->open_flags & BDRV_O_RDWR) {
+        s->header->inuse = 0;
+        parallels_update_header(bs);
+    }
+
     qemu_vfree(s->header);
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 20/27] iotests, parallels: check for incorrectly closed image in tests
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (18 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 19/27] block/parallels: implement incorrect close detection Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 14:39   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 21/27] block/parallels: no need to flush on each block allocation table update Denis V. Lunev
                   ` (6 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/115     |  9 +++++++++
 tests/qemu-iotests/115.out | 19 ++++++++++++++++++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115
index f45afa7..4873f40 100755
--- a/tests/qemu-iotests/115
+++ b/tests/qemu-iotests/115
@@ -42,6 +42,8 @@ _supported_fmt parallels
 _supported_proto file
 _supported_os Linux
 
+inuse_offset=$((0x2c))
+
 size=64M
 CLUSTER_SIZE=64k
 IMGFMT=parallels
@@ -62,6 +64,13 @@ echo == check that there is no trash after written ==
 echo == check that there is no trash before written ==
 { $QEMU_IO -c "read -P 0 0 32k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
 
+echo "== Corrupt image =="
+poke_file "$TEST_IMG" "$inuse_offset" "\x59\x6e\x6f\x74"
+{ $QEMU_IO -c "read -P 0x11 64k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+_check_test_img
+_check_test_img -r all
+{ $QEMU_IO -c "read -P 0x11 64k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/115.out b/tests/qemu-iotests/115.out
index 6a73104..5e93b3b 100644
--- a/tests/qemu-iotests/115.out
+++ b/tests/qemu-iotests/115.out
@@ -1,5 +1,5 @@
 QA output created by 115
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
 == read empty image ==
 read 65536/65536 bytes at offset 32768
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -21,4 +21,21 @@ read 32768/32768 bytes at offset 163840
 == check that there is no trash before written ==
 read 32768/32768 bytes at offset 0
 32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== Corrupt image ==
+qemu-io: can't open device TEST_DIR/t.parallels: parallels: Image was not closed correctly; cannot be opened read/write
+no file open, try 'help open'
+ERROR image was not closed correctly
+
+1 errors were found on the image.
+Data may be corrupted, or further writes to the image may corrupt it.
+Repairing image was not closed correctly
+The following inconsistencies were found and repaired:
+
+    0 leaked clusters
+    1 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
+read 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 *** done
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 21/27] block/parallels: no need to flush on each block allocation table update
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (19 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 20/27] iotests, parallels: check for incorrectly closed image in tests Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 14:41   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 22/27] block/parallels: improve image reading performance Denis V. Lunev
                   ` (5 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

>From the point of guest each write to real disk prior to disk barrier
operation could be lost. Therefore there is no problem that "not synced"
new block is lost due to not updated allocation table if QEMU is crashed.
This situation is properly detected and handled now using inuse magic
and in parallels_check

This patch improves writing performance of
  qemu-img create -f parallels -o cluster_size=64k ./1.hds 64G
  qemu-io -f parallels -c "write -P 0x11 0 1024k" 1.hds
from 45 Mb/sec to 160 Mb/sec on my SSD disk. The gain on rotational media
is much more sufficient, from 800 Kb/sec to 45 Mb/sec.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/block/parallels.c b/block/parallels.c
index 9933c49..e8b3d09 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -117,7 +117,7 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
     bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS);
 
     s->bat_bitmap[idx] = cpu_to_le32(pos / s->off_multiplier);
-    ret = bdrv_pwrite_sync(bs->file,
+    ret = bdrv_pwrite(bs->file,
             sizeof(ParallelsHeader) + idx * sizeof(s->bat_bitmap[idx]),
             s->bat_bitmap + idx, sizeof(s->bat_bitmap[idx]));
     if (ret < 0) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 22/27] block/parallels: improve image reading performance
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (20 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 21/27] block/parallels: no need to flush on each block allocation table update Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 14:50   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 23/27] block/parallels: create bat_entry_off helper Denis V. Lunev
                   ` (4 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

Try to perform IO for the biggest continuous block possible.
The performance for sequential read is increased from 220 Gb/sec to
360 Gb/sec for continous image on my SSD HDD.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 37 ++++++++++++++++++++++++++++++++-----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index e8b3d09..d0128c9 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -96,6 +96,35 @@ static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
     return MIN(nb_sectors, ret);
 }
 
+static int64_t block_status(BDRVParallelsState *s, int64_t sector_num,
+                            int nb_sectors, int *pnum)
+{
+    int64_t start_off = -2, prev_end_off = -2;
+
+    *pnum = 0;
+    while (nb_sectors > 0 || start_off == -2) {
+        int64_t offset = seek_to_sector(s, sector_num);
+        int to_end;
+
+        if (start_off == -2) {
+            start_off = offset;
+            prev_end_off = offset;
+        } else if (offset != prev_end_off) {
+            break;
+        }
+
+        to_end = cluster_remainder(s, sector_num, nb_sectors);
+        nb_sectors -= to_end;
+        sector_num += to_end;
+        *pnum += to_end;
+
+        if (offset > 0) {
+            prev_end_off += to_end;
+        }
+    }
+    return start_off;
+}
+
 static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
 {
     BDRVParallelsState *s = bs->opaque;
@@ -133,11 +162,9 @@ static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
     int64_t offset;
 
     qemu_co_mutex_lock(&s->lock);
-    offset = seek_to_sector(s, sector_num);
+    offset = block_status(s, sector_num, nb_sectors, pnum);
     qemu_co_mutex_unlock(&s->lock);
 
-    *pnum = cluster_remainder(s, sector_num, nb_sectors);
-
     if (offset < 0) {
         return 0;
     }
@@ -201,8 +228,8 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
 
     qemu_co_mutex_lock(&s->lock);
     while (nb_sectors > 0) {
-        int64_t position = seek_to_sector(s, sector_num);
-        int n = cluster_remainder(s, sector_num, nb_sectors);
+        int n;
+        int64_t position = block_status(s, sector_num, nb_sectors, &n);
         int nbytes = n << BDRV_SECTOR_BITS;
 
         if (position < 0) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 23/27] block/parallels: create bat_entry_off helper
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (21 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 22/27] block/parallels: improve image reading performance Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 14:52   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 24/27] block/parallels: delay writing to BAT till bdrv_co_flush_to_os Denis V. Lunev
                   ` (3 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

calculate offset of the BAT entry in the image file.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index d0128c9..70445b1 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -76,6 +76,11 @@ static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
     return (uint64_t)le32_to_cpu(s->bat_bitmap[idx]) * s->off_multiplier;
 }
 
+static uint32_t bat_entry_off(uint32_t idx)
+{
+    return sizeof(ParallelsHeader) + sizeof(uint32_t) * idx;
+}
+
 static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
 {
     uint32_t index, offset;
@@ -146,9 +151,8 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
     bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS);
 
     s->bat_bitmap[idx] = cpu_to_le32(pos / s->off_multiplier);
-    ret = bdrv_pwrite(bs->file,
-            sizeof(ParallelsHeader) + idx * sizeof(s->bat_bitmap[idx]),
-            s->bat_bitmap + idx, sizeof(s->bat_bitmap[idx]));
+    ret = bdrv_pwrite(bs->file, bat_entry_off(idx), s->bat_bitmap + idx,
+                      sizeof(s->bat_bitmap[idx]));
     if (ret < 0) {
         return ret;
     }
@@ -384,8 +388,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
     }
 
     bat_entries = DIV_ROUND_UP(total_size, cl_size);
-    bat_sectors = DIV_ROUND_UP(bat_entries * sizeof(uint32_t) +
-                               sizeof(ParallelsHeader), cl_size);
+    bat_sectors = DIV_ROUND_UP(bat_entry_off(bat_entries), cl_size);
     bat_sectors = (bat_sectors *  cl_size) >> BDRV_SECTOR_BITS;
 
     memset(&header, 0, sizeof(header));
@@ -495,7 +498,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         goto fail;
     }
 
-    size = sizeof(ParallelsHeader) + sizeof(uint32_t) * s->bat_size;
+    size = bat_entry_off(s->bat_size);
     s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file));
     s->header = qemu_try_blockalign(bs->file, s->header_size);
     if (s->header == NULL) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 24/27] block/parallels: delay writing to BAT till bdrv_co_flush_to_os
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (22 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 23/27] block/parallels: create bat_entry_off helper Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 15:04   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 25/27] block/parallels: add prealloc-mode and prealloc-size open paramemets Denis V. Lunev
                   ` (2 subsequent siblings)
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

The idea is that we do not need to immediately sync BAT to the image as
from the guest point of view there is a possibility that IO is lost
even in the physical controller until flush command was finished.
bdrv_co_flush_to_os is exactly the right place for this purpose.

Technically the patch uses loaded BAT data as a cache and performs
actual on-disk metadata updates in parallels_co_flush_to_os callback.

This patch speed ups
  qemu-img create -f parallels -o cluster_size=64k ./1.hds 64G
  qemu-io -f parallels -c "write -P 0x11 0 1024k" 1.hds
writing from 50-60 Mb/sec to 80-90 Mb/sec on rotational media and
from 160 Mb/sec to 190 Mb/sec on SSD disk.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 6 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 70445b1..b42bd07 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -30,6 +30,7 @@
 #include "qemu-common.h"
 #include "block/block_int.h"
 #include "qemu/module.h"
+#include "qemu/bitmap.h"
 
 /**************************************************************/
 
@@ -62,6 +63,9 @@ typedef struct BDRVParallelsState {
     uint32_t header_size;
     bool header_unclean;
 
+    unsigned long *bat_dirty_bmap;
+    unsigned int  bat_dirty_block;
+
     uint32_t *bat_bitmap;
     unsigned int bat_size;
 
@@ -135,7 +139,6 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
     BDRVParallelsState *s = bs->opaque;
     uint32_t idx, offset;
     int64_t pos;
-    int ret;
 
     idx = sector_num / s->tracks;
     offset = sector_num % s->tracks;
@@ -151,14 +154,43 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
     bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS);
 
     s->bat_bitmap[idx] = cpu_to_le32(pos / s->off_multiplier);
-    ret = bdrv_pwrite(bs->file, bat_entry_off(idx), s->bat_bitmap + idx,
-                      sizeof(s->bat_bitmap[idx]));
-    if (ret < 0) {
-        return ret;
-    }
+
+    bitmap_set(s->bat_dirty_bmap, bat_entry_off(idx) / s->bat_dirty_block, 1);
     return bat2sect(s, idx) + offset;
 }
 
+
+static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
+{
+    BDRVParallelsState *s = bs->opaque;
+    unsigned long size = DIV_ROUND_UP(s->header_size, s->bat_dirty_block);
+    unsigned long bit;
+
+    qemu_co_mutex_lock(&s->lock);
+
+    bit = find_first_bit(s->bat_dirty_bmap, size);
+    while (bit < size) {
+        uint32_t off = bit * s->bat_dirty_block;
+        uint32_t to_write = s->bat_dirty_block;
+        int ret;
+
+        if (off + to_write > s->header_size) {
+            to_write = s->header_size - off;
+        }
+        ret = bdrv_pwrite(bs->file, off, (uint8_t *)s->header + off, to_write);
+        if (ret < 0) {
+            qemu_co_mutex_unlock(&s->lock);
+            return ret;
+        }
+        bit = find_next_bit(s->bat_dirty_bmap, size, bit + 1);
+    }
+    bitmap_zero(s->bat_dirty_bmap, size);
+
+    qemu_co_mutex_unlock(&s->lock);
+    return 0;
+}
+
+
 static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, int *pnum)
 {
@@ -536,6 +568,10 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         }
     }
 
+    s->bat_dirty_block = 4 * getpagesize();
+    s->bat_dirty_bmap =
+        bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block));
+
     qemu_co_mutex_init(&s->lock);
     return 0;
 
@@ -557,6 +593,7 @@ static void parallels_close(BlockDriverState *bs)
         parallels_update_header(bs);
     }
 
+    g_free(s->bat_dirty_bmap);
     qemu_vfree(s->header);
 }
 
@@ -586,6 +623,7 @@ static BlockDriver bdrv_parallels = {
     .bdrv_open		= parallels_open,
     .bdrv_close		= parallels_close,
     .bdrv_co_get_block_status = parallels_co_get_block_status,
+    .bdrv_co_flush_to_os      = parallels_co_flush_to_os,
     .bdrv_co_readv  = parallels_co_readv,
     .bdrv_co_writev = parallels_co_writev,
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 25/27] block/parallels: add prealloc-mode and prealloc-size open paramemets
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (23 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 24/27] block/parallels: delay writing to BAT till bdrv_co_flush_to_os Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 15:05   ` Roman Kagan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 26/27] block/parallels: optimize linear image expansion Denis V. Lunev
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 27/27] block/parallels: improve image writing performance further Denis V. Lunev
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

This is preparational commit for tweaks in Parallels image expansion.
The idea is that enlarge via truncate by one data block is slow. It
would be much better to use fallocate via bdrv_write_zeroes and
expand by some significant amount at once.

This patch just adds proper parameters into BDRVParallelsState and
performs options parsing in parallels_open.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/block/parallels.c b/block/parallels.c
index b42bd07..989efe4 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -31,6 +31,7 @@
 #include "block/block_int.h"
 #include "qemu/module.h"
 #include "qemu/bitmap.h"
+#include "qapi/util.h"
 
 /**************************************************************/
 
@@ -56,6 +57,20 @@ typedef struct ParallelsHeader {
     char padding[12];
 } QEMU_PACKED ParallelsHeader;
 
+
+typedef enum ParallelsPreallocMode {
+    PRL_PREALLOC_MODE_FALLOCATE = 0,
+    PRL_PREALLOC_MODE_TRUNCATE = 1,
+    PRL_PREALLOC_MODE_MAX = 2,
+} ParallelsPreallocMode;
+
+static const char *prealloc_mode_lookup[] = {
+    "falloc",
+    "truncate",
+    NULL,
+};
+
+
 typedef struct BDRVParallelsState {
     CoMutex lock;
 
@@ -69,12 +84,40 @@ typedef struct BDRVParallelsState {
     uint32_t *bat_bitmap;
     unsigned int bat_size;
 
+    uint64_t prealloc_size;
+    ParallelsPreallocMode prealloc_mode;
+
     unsigned int tracks;
 
     unsigned int off_multiplier;
 } BDRVParallelsState;
 
 
+#define PARALLELS_OPT_PREALLOC_MODE     "prealloc-mode"
+#define PARALLELS_OPT_PREALLOC_SIZE     "prealloc-size"
+
+static QemuOptsList parallels_runtime_opts = {
+    .name = "parallels",
+    .head = QTAILQ_HEAD_INITIALIZER(parallels_runtime_opts.head),
+    .desc = {
+        {
+            .name = PARALLELS_OPT_PREALLOC_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Preallocation size on image expansion",
+            .def_value_str = "128MiB",
+        },
+        {
+            .name = PARALLELS_OPT_PREALLOC_MODE,
+            .type = QEMU_OPT_STRING,
+            .help = "Preallocation mode on image expansion "
+                    "(allowed values: falloc, truncate)",
+            .def_value_str = "falloc",
+        },
+        { /* end of list */ },
+    },
+};
+
+
 static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
 {
     return (uint64_t)le32_to_cpu(s->bat_bitmap[idx]) * s->off_multiplier;
@@ -491,6 +534,9 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     BDRVParallelsState *s = bs->opaque;
     ParallelsHeader ph;
     int ret, size;
+    QemuOpts *opts = NULL;
+    Error *local_err = NULL;
+    char *buf;
 
     ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
     if (ret < 0) {
@@ -560,6 +606,27 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         }
     }
 
+    opts = qemu_opts_create(&parallels_runtime_opts, NULL, 0, &local_err);
+    if (local_err != NULL) {
+        goto fail_options;
+    }
+
+    qemu_opts_absorb_qdict(opts, options, &local_err);
+    if (local_err != NULL) {
+        goto fail_options;
+    }
+
+    s->prealloc_size =
+        qemu_opt_get_size_del(opts, PARALLELS_OPT_PREALLOC_SIZE, 0);
+    s->prealloc_size = MAX(s->tracks, s->prealloc_size >> BDRV_SECTOR_BITS);
+    buf = qemu_opt_get_del(opts, PARALLELS_OPT_PREALLOC_MODE);
+    s->prealloc_mode = qapi_enum_parse(prealloc_mode_lookup, buf,
+            PRL_PREALLOC_MODE_MAX, PRL_PREALLOC_MODE_FALLOCATE, &local_err);
+    g_free(buf);
+    if (local_err != NULL) {
+        goto fail_options;
+    }
+
     if (flags & BDRV_O_RDWR) {
         s->header->inuse = cpu_to_le32(HEADER_INUSE_MAGIC);
         ret = parallels_update_header(bs);
@@ -581,6 +648,11 @@ fail_format:
 fail:
     qemu_vfree(s->header);
     return ret;
+
+fail_options:
+    error_propagate(errp, local_err);
+    ret = -EINVAL;
+    goto fail;
 }
 
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 26/27] block/parallels: optimize linear image expansion
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (24 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 25/27] block/parallels: add prealloc-mode and prealloc-size open paramemets Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-10 15:10   ` Roman Karan
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 27/27] block/parallels: improve image writing performance further Denis V. Lunev
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Karan

Plain image expansion spends a lot of time to update image file size.
This seriously affects the performance. The following simple test
  qemu_img create -f parallels -o cluster_size=64k ./1.hds 64G
  qemu_io -n -c "write -P 0x11 0 1024M" ./1.hds
could be improved if the format driver will pre-allocate some space
in the image file with a reasonable chunk.

This patch preallocates 128 Mb using bdrv_write_zeroes, which should
normally use fallocate() call inside. Fallback to older truncate()
could be used as a fallback using image open options thanks to the
previous patch.

The benefit is around 15%.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Karan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 989efe4..c6343c5 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -84,6 +84,7 @@ typedef struct BDRVParallelsState {
     uint32_t *bat_bitmap;
     unsigned int bat_size;
 
+    int64_t  data_end;
     uint64_t prealloc_size;
     ParallelsPreallocMode prealloc_mode;
 
@@ -194,7 +195,20 @@ static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
     }
 
     pos = bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS;
-    bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS);
+    if (s->data_end + s->tracks > pos) {
+        int ret;
+        if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE)
+            ret = bdrv_write_zeroes(bs->file, s->data_end,
+                                    s->prealloc_size, 0);
+        else
+            ret = bdrv_truncate(bs->file,
+                    (s->data_end + s->prealloc_size) << BDRV_SECTOR_BITS);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+    pos = s->data_end;
+    s->data_end += s->tracks;
 
     s->bat_bitmap[idx] = cpu_to_le32(pos / s->off_multiplier);
 
@@ -533,7 +547,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
 {
     BDRVParallelsState *s = bs->opaque;
     ParallelsHeader ph;
-    int ret, size;
+    int ret, size, i;
     QemuOpts *opts = NULL;
     Error *local_err = NULL;
     char *buf;
@@ -583,7 +597,11 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         ret = -ENOMEM;
         goto fail;
     }
-    if (le32_to_cpu(ph.data_off) < s->header_size) {
+    s->data_end = le32_to_cpu(ph.data_off);
+    if (s->data_end == 0) {
+        s->data_end = ROUND_UP(bat_entry_off(s->bat_size), BDRV_SECTOR_SIZE);
+    }
+    if (s->data_end < s->header_size) {
         /* there is not enough unused space to fit to block align between BAT
            and actual data. We can't avoid read-modify-write... */
         s->header_size = size;
@@ -595,6 +613,13 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     }
     s->bat_bitmap = (uint32_t *)(s->header + 1);
 
+    for (i = 0; i < s->bat_size; i++) {
+        int64_t off = bat2sect(s, i);
+        if (off >= s->data_end) {
+            s->data_end = off + s->tracks;
+        }
+    }
+
     if (le32_to_cpu(ph.inuse) == HEADER_INUSE_MAGIC) {
         /* Image was not closed correctly. The check is mandatory */
         s->header_unclean = true;
@@ -665,6 +690,10 @@ static void parallels_close(BlockDriverState *bs)
         parallels_update_header(bs);
     }
 
+    if (bs->open_flags & BDRV_O_RDWR) {
+        bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS);
+    }
+
     g_free(s->bat_dirty_bmap);
     qemu_vfree(s->header);
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 27/27] block/parallels: improve image writing performance further
  2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
                   ` (25 preceding siblings ...)
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 26/27] block/parallels: optimize linear image expansion Denis V. Lunev
@ 2015-03-10  8:51 ` Denis V. Lunev
  2015-03-11  9:25   ` Roman Kagan
  26 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10  8:51 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

Try to perform IO for the biggest continuous block possible.
All blocks abscent in the image are accounted in the same type
and preallocation is made for all of them at once.

The performance for sequential write is increased from 200 Gb/sec to
235 Gb/sec on my SSD HDD.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 44 ++++++++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 20 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index c6343c5..ccfdfab 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -178,42 +178,46 @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num,
     return start_off;
 }
 
-static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
+static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
+                                 int nb_sectors, int *pnum)
 {
     BDRVParallelsState *s = bs->opaque;
-    uint32_t idx, offset;
-    int64_t pos;
+    uint32_t idx, to_allocate, i;
+    int64_t pos, space;
 
-    idx = sector_num / s->tracks;
-    offset = sector_num % s->tracks;
+    pos = block_status(s, sector_num, nb_sectors, pnum);
+    if (pos > 0) {
+        return pos;
+    }
 
+    idx = sector_num / s->tracks;
     if (idx >= s->bat_size) {
         return -EINVAL;
     }
-    if (s->bat_bitmap[idx] != 0) {
-        return bat2sect(s, idx) + offset;
-    }
 
-    pos = bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS;
-    if (s->data_end + s->tracks > pos) {
+    to_allocate = (sector_num + *pnum + s->tracks - 1) / s->tracks - idx;
+    space = to_allocate * s->tracks;
+    if (s->data_end + space > bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS) {
         int ret;
+        space += s->prealloc_size;
         if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE)
-            ret = bdrv_write_zeroes(bs->file, s->data_end,
-                                    s->prealloc_size, 0);
+            ret = bdrv_write_zeroes(bs->file, s->data_end, space, 0);
         else
             ret = bdrv_truncate(bs->file,
-                    (s->data_end + s->prealloc_size) << BDRV_SECTOR_BITS);
+                                (s->data_end + space) << BDRV_SECTOR_BITS);
         if (ret < 0) {
             return ret;
         }
     }
-    pos = s->data_end;
-    s->data_end += s->tracks;
 
-    s->bat_bitmap[idx] = cpu_to_le32(pos / s->off_multiplier);
+    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;
+        bitmap_set(s->bat_dirty_bmap,
+                   bat_entry_off(idx) / s->bat_dirty_block, 1);
+    }
 
-    bitmap_set(s->bat_dirty_bmap, bat_entry_off(idx) / s->bat_dirty_block, 1);
-    return bat2sect(s, idx) + offset;
+    return bat2sect(s, idx) + sector_num % s->tracks;
 }
 
 
@@ -278,8 +282,8 @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
 
     qemu_co_mutex_lock(&s->lock);
     while (nb_sectors > 0) {
-        int64_t position = allocate_cluster(bs, sector_num);
-        int n = cluster_remainder(s, sector_num, nb_sectors);
+        int n;
+        int64_t position = allocate_clusters(bs, sector_num, nb_sectors, &n);
         int nbytes = n << BDRV_SECTOR_BITS;
 
         if (position < 0) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] block/parallels: create bat2sect helper
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 14/27] block/parallels: create bat2sect helper Denis V. Lunev
@ 2015-03-10 12:14   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 12:14 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:08AM +0300, Denis V. Lunev wrote:
> deduplicate copy/paste arithmetcs
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] block/parallels: keep BAT bitmap data in little endian in memory
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 15/27] block/parallels: keep BAT bitmap data in little endian in memory Denis V. Lunev
@ 2015-03-10 12:16   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 12:16 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:09AM +0300, Denis V. Lunev wrote:
> This will allow to use this data as buffer to BAT update directly
> without any intermediate buffers.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 15 +++++----------
>  1 file changed, 5 insertions(+), 10 deletions(-)

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 16/27] block/parallels: read parallels image header and BAT into single buffer
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 16/27] block/parallels: read parallels image header and BAT into single buffer Denis V. Lunev
@ 2015-03-10 14:07   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:07 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:10AM +0300, Denis V. Lunev wrote:
> This metadata cache would allow to properly batch BAT updates to disk
> in next patches. These updates will be properly aligned to avoid
> read-modify-write transactions on block level.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 24 +++++++++++++++++-------
>  1 file changed, 17 insertions(+), 7 deletions(-)

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 17/27] block/parallels: move parallels_open/probe to the very end of the file
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 17/27] block/parallels: move parallels_open/probe to the very end of the file Denis V. Lunev
@ 2015-03-10 14:09   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:09 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:11AM +0300, Denis V. Lunev wrote:
> This will help to avoid forward declarations for upcoming parallels_check
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 183 +++++++++++++++++++++++++++---------------------------
>  1 file changed, 93 insertions(+), 90 deletions(-)

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 18/27] block/parallels: implement parallels_check method of block driver
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 18/27] block/parallels: implement parallels_check method of block driver Denis V. Lunev
@ 2015-03-10 14:24   ` Roman Kagan
  2015-03-10 14:29     ` Denis V. Lunev
  0 siblings, 1 reply; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:24 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:12AM +0300, Denis V. Lunev wrote:
> The check is very simple at the moment. It calculates necessary stats
> and fix only the following errors:
> - space leak at the end of the image. This would happens due to
>   preallocation
> - clusters outside the image are zeroed. Nothing else could be done here
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 82 insertions(+)
> 
> diff --git a/block/parallels.c b/block/parallels.c
> index 65f6418..e5b475e 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
> @@ -228,6 +228,87 @@ fail:
>      return ret;
>  }
>  
> +
> +static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
> +                           BdrvCheckMode fix)
> +{
> +    BDRVParallelsState *s = bs->opaque;
> +    int64_t size, prev_off, high_off;
> +    int ret;
> +    uint32_t i;
> +    bool flush_bat = false;
> +    int cluster_size = s->tracks << BDRV_SECTOR_BITS;
> +
> +    size = bdrv_getlength(bs->file);
> +    if (size < 0) {
> +        res->check_errors++;
> +        return size;
> +    }
> +
> +    res->bfi.total_clusters = s->bat_size;
> +    res->bfi.compressed_clusters = 0; /* compression is not supported */
> +
> +    high_off = 0;
> +    prev_off = 0;
> +    for (i = 0; i < s->bat_size; i++) {
> +        int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
> +        if (off == 0)
> +            continue;

If you don't update prev_off here you can get fragmentation stats wrong
(dunno how important it is)

> +
> +        /* cluster outside the image */
> +        if (off > size) {
> +            fprintf(stderr, "%s cluster %u is outside image\n",
> +                    fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
> +            res->corruptions++;
> +            if (fix & BDRV_FIX_ERRORS) {
> +                s->bat_bitmap[i] = 0;
> +                res->corruptions_fixed++;
> +                flush_bat = true;
> +                continue;
> +            }

Ditto

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 18/27] block/parallels: implement parallels_check method of block driver
  2015-03-10 14:24   ` Roman Kagan
@ 2015-03-10 14:29     ` Denis V. Lunev
  0 siblings, 0 replies; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10 14:29 UTC (permalink / raw)
  To: Roman Kagan, Kevin Wolf, qemu-devel, Stefan Hajnoczi

On 10/03/15 17:24, Roman Kagan wrote:
> On Tue, Mar 10, 2015 at 11:51:12AM +0300, Denis V. Lunev wrote:
>> The check is very simple at the moment. It calculates necessary stats
>> and fix only the following errors:
>> - space leak at the end of the image. This would happens due to
>>    preallocation
>> - clusters outside the image are zeroed. Nothing else could be done here
>>
>> Signed-off-by: Denis V. Lunev <den@openvz.org>
>> CC: Roman Kagan <rkagan@parallels.com>
>> CC: Kevin Wolf <kwolf@redhat.com>
>> CC: Stefan Hajnoczi <stefanha@redhat.com>
>> ---
>>   block/parallels.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 82 insertions(+)
>>
>> diff --git a/block/parallels.c b/block/parallels.c
>> index 65f6418..e5b475e 100644
>> --- a/block/parallels.c
>> +++ b/block/parallels.c
>> @@ -228,6 +228,87 @@ fail:
>>       return ret;
>>   }
>>   
>> +
>> +static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
>> +                           BdrvCheckMode fix)
>> +{
>> +    BDRVParallelsState *s = bs->opaque;
>> +    int64_t size, prev_off, high_off;
>> +    int ret;
>> +    uint32_t i;
>> +    bool flush_bat = false;
>> +    int cluster_size = s->tracks << BDRV_SECTOR_BITS;
>> +
>> +    size = bdrv_getlength(bs->file);
>> +    if (size < 0) {
>> +        res->check_errors++;
>> +        return size;
>> +    }
>> +
>> +    res->bfi.total_clusters = s->bat_size;
>> +    res->bfi.compressed_clusters = 0; /* compression is not supported */
>> +
>> +    high_off = 0;
>> +    prev_off = 0;
>> +    for (i = 0; i < s->bat_size; i++) {
>> +        int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
>> +        if (off == 0)
>> +            continue;
> If you don't update prev_off here you can get fragmentation stats wrong
> (dunno how important it is)

ok. by the way, I have missed braces here...

>> +
>> +        /* cluster outside the image */
>> +        if (off > size) {
>> +            fprintf(stderr, "%s cluster %u is outside image\n",
>> +                    fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
>> +            res->corruptions++;
>> +            if (fix & BDRV_FIX_ERRORS) {
>> +                s->bat_bitmap[i] = 0;
>> +                res->corruptions_fixed++;
>> +                flush_bat = true;
>> +                continue;
>> +            }
> Ditto
>
> Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 19/27] block/parallels: implement incorrect close detection
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 19/27] block/parallels: implement incorrect close detection Denis V. Lunev
@ 2015-03-10 14:38   ` Roman Kagan
  2015-03-10 14:44     ` Denis V. Lunev
  0 siblings, 1 reply; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:38 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:13AM +0300, Denis V. Lunev wrote:
> The software driver must set inuse field in Parallels header to
> 0x746F6E59 when the image is opened in read-write mode. The presence of
> this magic in the header on open forces image consistency check.
> 
> There is an unfortunate trick here. We can not check for inuse in
> parallels_check as this will happen too late. It is possible to do
> that for simple check, but during the fix this would always report
> an error as the image was opened in BDRV_O_RDWR mode. Thus we save
> the flag in BDRVParallelsState for this.
> 
> On the other hand, nothing should be done to clear inuse in
> parallels_check. Generic close will do the job right.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 50 insertions(+)

> @@ -462,6 +487,25 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>      s->bat_bitmap = (uint32_t *)(s->header + 1);
>  
> +    if (le32_to_cpu(ph.inuse) == HEADER_INUSE_MAGIC) {
> +        /* Image was not closed correctly. The check is mandatory */
> +        s->header_unclean = true;
> +        if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_CHECK)) {
> +            error_setg(errp, "parallels: Image was not closed correctly; "
> +                       "cannot be opened read/write");
> +            ret = -EACCES;

-EBUSY?

Otherwise looks ok.

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 20/27] iotests, parallels: check for incorrectly closed image in tests
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 20/27] iotests, parallels: check for incorrectly closed image in tests Denis V. Lunev
@ 2015-03-10 14:39   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:39 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:14AM +0300, Denis V. Lunev wrote:
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  tests/qemu-iotests/115     |  9 +++++++++
>  tests/qemu-iotests/115.out | 19 ++++++++++++++++++-
>  2 files changed, 27 insertions(+), 1 deletion(-)


Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 21/27] block/parallels: no need to flush on each block allocation table update
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 21/27] block/parallels: no need to flush on each block allocation table update Denis V. Lunev
@ 2015-03-10 14:41   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:41 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:15AM +0300, Denis V. Lunev wrote:
> From the point of guest each write to real disk prior to disk barrier
> operation could be lost. Therefore there is no problem that "not synced"
> new block is lost due to not updated allocation table if QEMU is crashed.
> This situation is properly detected and handled now using inuse magic
> and in parallels_check
> 
> This patch improves writing performance of
>   qemu-img create -f parallels -o cluster_size=64k ./1.hds 64G
>   qemu-io -f parallels -c "write -P 0x11 0 1024k" 1.hds
> from 45 Mb/sec to 160 Mb/sec on my SSD disk. The gain on rotational media
> is much more sufficient, from 800 Kb/sec to 45 Mb/sec.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 19/27] block/parallels: implement incorrect close detection
  2015-03-10 14:38   ` Roman Kagan
@ 2015-03-10 14:44     ` Denis V. Lunev
  2015-03-10 14:51       ` Roman Kagan
  0 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-10 14:44 UTC (permalink / raw)
  To: Roman Kagan, Kevin Wolf, qemu-devel, Stefan Hajnoczi

On 10/03/15 17:38, Roman Kagan wrote:
> On Tue, Mar 10, 2015 at 11:51:13AM +0300, Denis V. Lunev wrote:
>> The software driver must set inuse field in Parallels header to
>> 0x746F6E59 when the image is opened in read-write mode. The presence of
>> this magic in the header on open forces image consistency check.
>>
>> There is an unfortunate trick here. We can not check for inuse in
>> parallels_check as this will happen too late. It is possible to do
>> that for simple check, but during the fix this would always report
>> an error as the image was opened in BDRV_O_RDWR mode. Thus we save
>> the flag in BDRVParallelsState for this.
>>
>> On the other hand, nothing should be done to clear inuse in
>> parallels_check. Generic close will do the job right.
>>
>> Signed-off-by: Denis V. Lunev <den@openvz.org>
>> CC: Roman Kagan <rkagan@parallels.com>
>> CC: Kevin Wolf <kwolf@redhat.com>
>> CC: Stefan Hajnoczi <stefanha@redhat.com>
>> ---
>>   block/parallels.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 50 insertions(+)
>> @@ -462,6 +487,25 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>>       }
>>       s->bat_bitmap = (uint32_t *)(s->header + 1);
>>   
>> +    if (le32_to_cpu(ph.inuse) == HEADER_INUSE_MAGIC) {
>> +        /* Image was not closed correctly. The check is mandatory */
>> +        s->header_unclean = true;
>> +        if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_CHECK)) {
>> +            error_setg(errp, "parallels: Image was not closed correctly; "
>> +                       "cannot be opened read/write");
>> +            ret = -EACCES;
> -EBUSY?
>
> Otherwise looks ok.
>
> Roman.
error code is the same as one in qcow2

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 22/27] block/parallels: improve image reading performance
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 22/27] block/parallels: improve image reading performance Denis V. Lunev
@ 2015-03-10 14:50   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:50 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:16AM +0300, Denis V. Lunev wrote:
> Try to perform IO for the biggest continuous block possible.
> The performance for sequential read is increased from 220 Gb/sec to
> 360 Gb/sec for continous image on my SSD HDD.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 37 ++++++++++++++++++++++++++++++++-----
>  1 file changed, 32 insertions(+), 5 deletions(-)


Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 19/27] block/parallels: implement incorrect close detection
  2015-03-10 14:44     ` Denis V. Lunev
@ 2015-03-10 14:51       ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:51 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 05:44:19PM +0300, Denis V. Lunev wrote:
> On 10/03/15 17:38, Roman Kagan wrote:
> >On Tue, Mar 10, 2015 at 11:51:13AM +0300, Denis V. Lunev wrote:
> >>The software driver must set inuse field in Parallels header to
> >>0x746F6E59 when the image is opened in read-write mode. The presence of
> >>this magic in the header on open forces image consistency check.
> >>
> >>There is an unfortunate trick here. We can not check for inuse in
> >>parallels_check as this will happen too late. It is possible to do
> >>that for simple check, but during the fix this would always report
> >>an error as the image was opened in BDRV_O_RDWR mode. Thus we save
> >>the flag in BDRVParallelsState for this.
> >>
> >>On the other hand, nothing should be done to clear inuse in
> >>parallels_check. Generic close will do the job right.
> >>
> >>Signed-off-by: Denis V. Lunev <den@openvz.org>
> >>CC: Roman Kagan <rkagan@parallels.com>
> >>CC: Kevin Wolf <kwolf@redhat.com>
> >>CC: Stefan Hajnoczi <stefanha@redhat.com>
> >>---
> >>  block/parallels.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 50 insertions(+)
> >>@@ -462,6 +487,25 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
> >>      }
> >>      s->bat_bitmap = (uint32_t *)(s->header + 1);
> >>+    if (le32_to_cpu(ph.inuse) == HEADER_INUSE_MAGIC) {
> >>+        /* Image was not closed correctly. The check is mandatory */
> >>+        s->header_unclean = true;
> >>+        if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_CHECK)) {
> >>+            error_setg(errp, "parallels: Image was not closed correctly; "
> >>+                       "cannot be opened read/write");
> >>+            ret = -EACCES;
> >-EBUSY?
> >
> >Otherwise looks ok.
> >
> >Roman.
> error code is the same as one in qcow2

OK then

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] block/parallels: create bat_entry_off helper
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 23/27] block/parallels: create bat_entry_off helper Denis V. Lunev
@ 2015-03-10 14:52   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 14:52 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:17AM +0300, Denis V. Lunev wrote:
> calculate offset of the BAT entry in the image file.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 15 +++++++++------
>  1 file changed, 9 insertions(+), 6 deletions(-)


Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 24/27] block/parallels: delay writing to BAT till bdrv_co_flush_to_os
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 24/27] block/parallels: delay writing to BAT till bdrv_co_flush_to_os Denis V. Lunev
@ 2015-03-10 15:04   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 15:04 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:18AM +0300, Denis V. Lunev wrote:
> The idea is that we do not need to immediately sync BAT to the image as
> from the guest point of view there is a possibility that IO is lost
> even in the physical controller until flush command was finished.
> bdrv_co_flush_to_os is exactly the right place for this purpose.
> 
> Technically the patch uses loaded BAT data as a cache and performs
> actual on-disk metadata updates in parallels_co_flush_to_os callback.
> 
> This patch speed ups
>   qemu-img create -f parallels -o cluster_size=64k ./1.hds 64G
>   qemu-io -f parallels -c "write -P 0x11 0 1024k" 1.hds
> writing from 50-60 Mb/sec to 80-90 Mb/sec on rotational media and
> from 160 Mb/sec to 190 Mb/sec on SSD disk.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 44 insertions(+), 6 deletions(-)

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 25/27] block/parallels: add prealloc-mode and prealloc-size open paramemets
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 25/27] block/parallels: add prealloc-mode and prealloc-size open paramemets Denis V. Lunev
@ 2015-03-10 15:05   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-10 15:05 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:19AM +0300, Denis V. Lunev wrote:
> This is preparational commit for tweaks in Parallels image expansion.
> The idea is that enlarge via truncate by one data block is slow. It
> would be much better to use fallocate via bdrv_write_zeroes and
> expand by some significant amount at once.
> 
> This patch just adds proper parameters into BDRVParallelsState and
> performs options parsing in parallels_open.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 72 insertions(+)

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 26/27] block/parallels: optimize linear image expansion
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 26/27] block/parallels: optimize linear image expansion Denis V. Lunev
@ 2015-03-10 15:10   ` Roman Karan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Karan @ 2015-03-10 15:10 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:20AM +0300, Denis V. Lunev wrote:
> Plain image expansion spends a lot of time to update image file size.
> This seriously affects the performance. The following simple test
>   qemu_img create -f parallels -o cluster_size=64k ./1.hds 64G
>   qemu_io -n -c "write -P 0x11 0 1024M" ./1.hds
> could be improved if the format driver will pre-allocate some space
> in the image file with a reasonable chunk.
> 
> This patch preallocates 128 Mb using bdrv_write_zeroes, which should
> normally use fallocate() call inside. Fallback to older truncate()
> could be used as a fallback using image open options thanks to the
> previous patch.
> 
> The benefit is around 15%.


Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 27/27] block/parallels: improve image writing performance further
  2015-03-10  8:51 ` [Qemu-devel] [PATCH 27/27] block/parallels: improve image writing performance further Denis V. Lunev
@ 2015-03-11  9:25   ` Roman Kagan
  0 siblings, 0 replies; 51+ messages in thread
From: Roman Kagan @ 2015-03-11  9:25 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Tue, Mar 10, 2015 at 11:51:21AM +0300, Denis V. Lunev wrote:
> Try to perform IO for the biggest continuous block possible.
> All blocks abscent in the image are accounted in the same type
> and preallocation is made for all of them at once.
> 
> The performance for sequential write is increased from 200 Gb/sec to
> 235 Gb/sec on my SSD HDD.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Roman Kagan <rkagan@parallels.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 44 ++++++++++++++++++++++++--------------------
>  1 file changed, 24 insertions(+), 20 deletions(-)

Reviewed-by: Roman Kagan <rkagan@parallels.com>

Roman.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read
  2015-04-28  7:46 ` [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read Denis V. Lunev
@ 2015-05-18 16:11   ` Stefan Hajnoczi
  0 siblings, 0 replies; 51+ messages in thread
From: Stefan Hajnoczi @ 2015-05-18 16:11 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Roman Kagan

[-- Attachment #1: Type: text/plain, Size: 817 bytes --]

On Tue, Apr 28, 2015 at 10:46:36AM +0300, Denis V. Lunev wrote:
> From: Roman Kagan <rkagan@parallels.com>
> 
> Switch the .bdrv_read method implementation from using bdrv_pread() to
> bdrv_read() on the underlying file, since the latter is subject to i/o
> throttling while the former is not.
> 
> Besides, since bdrv_read() operates in sectors rather than bytes, adjust
> the helper functions to do so too.
> 
> Signed-off-by: Roman Kagan <rkagan@parallels.com>
> Reviewed-by: Denis V. Lunev <den@openvz.org>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 20 +++++++++++---------
>  1 file changed, 11 insertions(+), 9 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read
  2015-04-28  7:46 [Qemu-devel] [PATCH v4 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
@ 2015-04-28  7:46 ` Denis V. Lunev
  2015-05-18 16:11   ` Stefan Hajnoczi
  0 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-04-28  7:46 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

From: Roman Kagan <rkagan@parallels.com>

Switch the .bdrv_read method implementation from using bdrv_pread() to
bdrv_read() on the underlying file, since the latter is subject to i/o
throttling while the former is not.

Besides, since bdrv_read() operates in sectors rather than bytes, adjust
the helper functions to do so too.

Signed-off-by: Roman Kagan <rkagan@parallels.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index dca0df6..baefd3e 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -146,9 +146,8 @@ fail:
     return ret;
 }
 
-static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
+static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
 {
-    BDRVParallelsState *s = bs->opaque;
     uint32_t index, offset;
 
     index = sector_num / s->tracks;
@@ -157,24 +156,27 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
     /* not allocated */
     if ((index >= s->catalog_size) || (s->catalog_bitmap[index] == 0))
         return -1;
-    return
-        ((uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset) * 512;
+    return (uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset;
 }
 
 static int parallels_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
+    BDRVParallelsState *s = bs->opaque;
+
     while (nb_sectors > 0) {
-        int64_t position = seek_to_sector(bs, sector_num);
+        int64_t position = seek_to_sector(s, sector_num);
         if (position >= 0) {
-            if (bdrv_pread(bs->file, position, buf, 512) != 512)
-                return -1;
+            int ret = bdrv_read(bs->file, position, buf, 1);
+            if (ret < 0) {
+                return ret;
+            }
         } else {
-            memset(buf, 0, 512);
+            memset(buf, 0, BDRV_SECTOR_SIZE);
         }
         nb_sectors--;
         sector_num++;
-        buf += 512;
+        buf += BDRV_SECTOR_SIZE;
     }
     return 0;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read
  2015-04-22 12:30     ` Denis V. Lunev
@ 2015-04-23  8:48       ` Stefan Hajnoczi
  0 siblings, 0 replies; 51+ messages in thread
From: Stefan Hajnoczi @ 2015-04-23  8:48 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, Stefan Hajnoczi, qemu-devel, Roman Kagan

[-- Attachment #1: Type: text/plain, Size: 993 bytes --]

On Wed, Apr 22, 2015 at 03:30:50PM +0300, Denis V. Lunev wrote:
> On 22/04/15 15:23, Stefan Hajnoczi wrote:
> >On Wed, Mar 11, 2015 at 01:27:57PM +0300, Denis V. Lunev wrote:
> >>From: Roman Kagan <rkagan@parallels.com>
> >>
> >>Switch the .bdrv_read method implementation from using bdrv_pread() to
> >>bdrv_read() on the underlying file, since the latter is subject to i/o
> >>throttling while the former is not.
> >>
> >>Besides, since bdrv_read() operates in sectors rather than bytes, adjust
> >>the helper functions to do so too.
> >Can this patch be dropped since "[PATCH 06/27] block/parallels: provide
> >_co_readv routine for parallels format driver" switches to
> >.bdrv_co_readv() anyway?
> >
> >Stefan
> this is not that easy. This patch changes seek_to_sector call and
> in reality to drop it I have to merge patches 3, 4 and 6.
> Besides that this patch has been written by my colleague and
> I feel comfortable to preserve original Signed-off-by of him.

I understand.

Stefan

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read
  2015-04-22 12:23   ` Stefan Hajnoczi
@ 2015-04-22 12:30     ` Denis V. Lunev
  2015-04-23  8:48       ` Stefan Hajnoczi
  0 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-04-22 12:30 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi, Roman Kagan

On 22/04/15 15:23, Stefan Hajnoczi wrote:
> On Wed, Mar 11, 2015 at 01:27:57PM +0300, Denis V. Lunev wrote:
>> From: Roman Kagan <rkagan@parallels.com>
>>
>> Switch the .bdrv_read method implementation from using bdrv_pread() to
>> bdrv_read() on the underlying file, since the latter is subject to i/o
>> throttling while the former is not.
>>
>> Besides, since bdrv_read() operates in sectors rather than bytes, adjust
>> the helper functions to do so too.
> Can this patch be dropped since "[PATCH 06/27] block/parallels: provide
> _co_readv routine for parallels format driver" switches to
> .bdrv_co_readv() anyway?
>
> Stefan
this is not that easy. This patch changes seek_to_sector call and
in reality to drop it I have to merge patches 3, 4 and 6.
Besides that this patch has been written by my colleague and
I feel comfortable to preserve original Signed-off-by of him.

Den

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read
  2015-03-11 10:27 ` [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read Denis V. Lunev
@ 2015-04-22 12:23   ` Stefan Hajnoczi
  2015-04-22 12:30     ` Denis V. Lunev
  0 siblings, 1 reply; 51+ messages in thread
From: Stefan Hajnoczi @ 2015-04-22 12:23 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi, Roman Kagan

[-- Attachment #1: Type: text/plain, Size: 589 bytes --]

On Wed, Mar 11, 2015 at 01:27:57PM +0300, Denis V. Lunev wrote:
> From: Roman Kagan <rkagan@parallels.com>
> 
> Switch the .bdrv_read method implementation from using bdrv_pread() to
> bdrv_read() on the underlying file, since the latter is subject to i/o
> throttling while the former is not.
> 
> Besides, since bdrv_read() operates in sectors rather than bytes, adjust
> the helper functions to do so too.

Can this patch be dropped since "[PATCH 06/27] block/parallels: provide
_co_readv routine for parallels format driver" switches to
.bdrv_co_readv() anyway?

Stefan

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read
  2015-03-11 10:27 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
@ 2015-03-11 10:27 ` Denis V. Lunev
  2015-04-22 12:23   ` Stefan Hajnoczi
  0 siblings, 1 reply; 51+ messages in thread
From: Denis V. Lunev @ 2015-03-11 10:27 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, qemu-devel, Stefan Hajnoczi, Roman Kagan

From: Roman Kagan <rkagan@parallels.com>

Switch the .bdrv_read method implementation from using bdrv_pread() to
bdrv_read() on the underlying file, since the latter is subject to i/o
throttling while the former is not.

Besides, since bdrv_read() operates in sectors rather than bytes, adjust
the helper functions to do so too.

Signed-off-by: Roman Kagan <rkagan@parallels.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index dca0df6..baefd3e 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -146,9 +146,8 @@ fail:
     return ret;
 }
 
-static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
+static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
 {
-    BDRVParallelsState *s = bs->opaque;
     uint32_t index, offset;
 
     index = sector_num / s->tracks;
@@ -157,24 +156,27 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
     /* not allocated */
     if ((index >= s->catalog_size) || (s->catalog_bitmap[index] == 0))
         return -1;
-    return
-        ((uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset) * 512;
+    return (uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset;
 }
 
 static int parallels_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
+    BDRVParallelsState *s = bs->opaque;
+
     while (nb_sectors > 0) {
-        int64_t position = seek_to_sector(bs, sector_num);
+        int64_t position = seek_to_sector(s, sector_num);
         if (position >= 0) {
-            if (bdrv_pread(bs->file, position, buf, 512) != 512)
-                return -1;
+            int ret = bdrv_read(bs->file, position, buf, 1);
+            if (ret < 0) {
+                return ret;
+            }
         } else {
-            memset(buf, 0, 512);
+            memset(buf, 0, BDRV_SECTOR_SIZE);
         }
         nb_sectors--;
         sector_num++;
-        buf += 512;
+        buf += BDRV_SECTOR_SIZE;
     }
     return 0;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2015-05-18 16:11 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-10  8:50 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
2015-03-10  8:50 ` [Qemu-devel] [PATCH 01/27] iotests, parallels: quote TEST_IMG in 076 test to be path-safe Denis V. Lunev
2015-03-10  8:50 ` [Qemu-devel] [PATCH 02/27] block/parallels: rename parallels_header to ParallelsHeader Denis V. Lunev
2015-03-10  8:50 ` [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read Denis V. Lunev
2015-03-10  8:50 ` [Qemu-devel] [PATCH 04/27] block/parallels: read up to cluster end in one go Denis V. Lunev
2015-03-10  8:50 ` [Qemu-devel] [PATCH 05/27] block/parallels: add get_block_status Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 06/27] block/parallels: provide _co_readv routine for parallels format driver Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 07/27] block/parallels: replace magic constants 4, 64 with proper sizeofs Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 08/27] block/parallels: _co_writev callback for Parallels format Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 09/27] iotests, parallels: test for write into Parallels image Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 10/27] block/parallels: support parallels image creation Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 11/27] iotests, parallels: test for newly created parallels image via qemu-img Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 12/27] parallels: change copyright information in the image header Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 13/27] block/parallels: rename catalog_ names to bat_ Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 14/27] block/parallels: create bat2sect helper Denis V. Lunev
2015-03-10 12:14   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 15/27] block/parallels: keep BAT bitmap data in little endian in memory Denis V. Lunev
2015-03-10 12:16   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 16/27] block/parallels: read parallels image header and BAT into single buffer Denis V. Lunev
2015-03-10 14:07   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 17/27] block/parallels: move parallels_open/probe to the very end of the file Denis V. Lunev
2015-03-10 14:09   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 18/27] block/parallels: implement parallels_check method of block driver Denis V. Lunev
2015-03-10 14:24   ` Roman Kagan
2015-03-10 14:29     ` Denis V. Lunev
2015-03-10  8:51 ` [Qemu-devel] [PATCH 19/27] block/parallels: implement incorrect close detection Denis V. Lunev
2015-03-10 14:38   ` Roman Kagan
2015-03-10 14:44     ` Denis V. Lunev
2015-03-10 14:51       ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 20/27] iotests, parallels: check for incorrectly closed image in tests Denis V. Lunev
2015-03-10 14:39   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 21/27] block/parallels: no need to flush on each block allocation table update Denis V. Lunev
2015-03-10 14:41   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 22/27] block/parallels: improve image reading performance Denis V. Lunev
2015-03-10 14:50   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 23/27] block/parallels: create bat_entry_off helper Denis V. Lunev
2015-03-10 14:52   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 24/27] block/parallels: delay writing to BAT till bdrv_co_flush_to_os Denis V. Lunev
2015-03-10 15:04   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 25/27] block/parallels: add prealloc-mode and prealloc-size open paramemets Denis V. Lunev
2015-03-10 15:05   ` Roman Kagan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 26/27] block/parallels: optimize linear image expansion Denis V. Lunev
2015-03-10 15:10   ` Roman Karan
2015-03-10  8:51 ` [Qemu-devel] [PATCH 27/27] block/parallels: improve image writing performance further Denis V. Lunev
2015-03-11  9:25   ` Roman Kagan
2015-03-11 10:27 [Qemu-devel] [PATCH v3 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
2015-03-11 10:27 ` [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read Denis V. Lunev
2015-04-22 12:23   ` Stefan Hajnoczi
2015-04-22 12:30     ` Denis V. Lunev
2015-04-23  8:48       ` Stefan Hajnoczi
2015-04-28  7:46 [Qemu-devel] [PATCH v4 0/27] write/create for Parallels images with reasonable performance Denis V. Lunev
2015-04-28  7:46 ` [Qemu-devel] [PATCH 03/27] block/parallels: switch to bdrv_read Denis V. Lunev
2015-05-18 16:11   ` Stefan Hajnoczi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.