From f287c41381efe172ff5dc62498e2afc83a9ab995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sun, 1 Dec 2013 22:23:34 +0100 Subject: [PATCH 01/48] coroutine: remove qemu_co_queue_wait_insert_head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu_co_queue_wait_insert_head() is unused in qemu code base now. Signed-off-by: Marc-André Lureau Signed-off-by: Stefan Hajnoczi --- include/block/coroutine.h | 6 ------ qemu-coroutine-lock.c | 8 -------- 2 files changed, 14 deletions(-) diff --git a/include/block/coroutine.h b/include/block/coroutine.h index 4d5c0cfdd7..b122c0c4fb 100644 --- a/include/block/coroutine.h +++ b/include/block/coroutine.h @@ -120,12 +120,6 @@ void qemu_co_queue_init(CoQueue *queue); */ void coroutine_fn qemu_co_queue_wait(CoQueue *queue); -/** - * Adds the current coroutine to the head of the CoQueue and transfers control to the - * caller of the coroutine. - */ -void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue); - /** * Restarts the next coroutine in the CoQueue and removes it from the queue. * diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c index aeb33b9118..e4860ae42f 100644 --- a/qemu-coroutine-lock.c +++ b/qemu-coroutine-lock.c @@ -41,14 +41,6 @@ void coroutine_fn qemu_co_queue_wait(CoQueue *queue) assert(qemu_in_coroutine()); } -void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue) -{ - Coroutine *self = qemu_coroutine_self(); - QTAILQ_INSERT_HEAD(&queue->entries, self, co_queue_next); - qemu_coroutine_yield(); - assert(qemu_in_coroutine()); -} - /** * qemu_co_queue_run_restart: * From 7b6b145dbc62162df818dc2c5153defd0417c688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sun, 1 Dec 2013 22:23:47 +0100 Subject: [PATCH 02/48] coroutine: remove unused CoQueue AioContext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AioContext ctx field is apparently unused in qemu codebase since 02ffb504485. Signed-off-by: Marc-André Lureau Signed-off-by: Stefan Hajnoczi --- include/block/coroutine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/block/coroutine.h b/include/block/coroutine.h index b122c0c4fb..a1797ae3d8 100644 --- a/include/block/coroutine.h +++ b/include/block/coroutine.h @@ -105,7 +105,6 @@ bool qemu_in_coroutine(void); */ typedef struct CoQueue { QTAILQ_HEAD(, Coroutine) entries; - AioContext *ctx; } CoQueue; /** From af057fe74092df2e7a576448ddbdc0daac1370bf Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 3 Dec 2013 10:41:05 +0800 Subject: [PATCH 03/48] vmdk: Fix creating big description file The buffer for description file was 4096 which only covers a few hundred of extents. This changes the buffer to dynamic allocated with g_strdup_printf in order to support bigger cases. Signed-off-by: Fam Zheng Signed-off-by: Stefan Hajnoczi --- block/vmdk.c | 62 +- tests/qemu-iotests/059 | 5 + tests/qemu-iotests/059.out | 2012 ++++++++++++++++++++++++++++++++++++ 3 files changed, 2055 insertions(+), 24 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 88d09e3e16..eb84f46a7b 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1596,7 +1596,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, Error **errp) { int fd, idx = 0; - char desc[BUF_SIZE]; + char *desc = NULL; int64_t total_size = 0, filesize; const char *adapter_type = NULL; const char *backing_file = NULL; @@ -1604,7 +1604,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, int flags = 0; int ret = 0; bool flat, split, compress; - char ext_desc_lines[BUF_SIZE] = ""; + GString *ext_desc_lines; char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX]; const int64_t split_size = 0x80000000; /* VMDK has constant split size */ const char *desc_extent_line; @@ -1632,8 +1632,11 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, "ddb.geometry.sectors = \"63\"\n" "ddb.adapterType = \"%s\"\n"; + ext_desc_lines = g_string_new(NULL); + if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) { - return -EINVAL; + ret = -EINVAL; + goto exit; } /* Read out options */ while (options && options->name) { @@ -1659,7 +1662,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, strcmp(adapter_type, "lsilogic") && strcmp(adapter_type, "legacyESX")) { error_setg(errp, "Unknown adapter type: '%s'", adapter_type); - return -EINVAL; + ret = -EINVAL; + goto exit; } if (strcmp(adapter_type, "ide") != 0) { /* that's the number of heads with which vmware operates when @@ -1675,7 +1679,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, strcmp(fmt, "twoGbMaxExtentFlat") && strcmp(fmt, "streamOptimized")) { error_setg(errp, "Unknown subformat: '%s'", fmt); - return -EINVAL; + ret = -EINVAL; + goto exit; } split = !(strcmp(fmt, "twoGbMaxExtentFlat") && strcmp(fmt, "twoGbMaxExtentSparse")); @@ -1689,22 +1694,25 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, } if (flat && backing_file) { error_setg(errp, "Flat image can't have backing file"); - return -ENOTSUP; + ret = -ENOTSUP; + goto exit; } if (flat && zeroed_grain) { error_setg(errp, "Flat image can't enable zeroed grain"); - return -ENOTSUP; + ret = -ENOTSUP; + goto exit; } if (backing_file) { BlockDriverState *bs = bdrv_new(""); ret = bdrv_open(bs, backing_file, NULL, BDRV_O_NO_BACKING, NULL, errp); if (ret != 0) { bdrv_unref(bs); - return ret; + goto exit; } if (strcmp(bs->drv->format_name, "vmdk")) { bdrv_unref(bs); - return -EINVAL; + ret = -EINVAL; + goto exit; } parent_cid = vmdk_read_cid(bs, 0); bdrv_unref(bs); @@ -1738,25 +1746,27 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, if (vmdk_create_extent(ext_filename, size, flat, compress, zeroed_grain)) { - return -EINVAL; + ret = -EINVAL; + goto exit; } filesize -= size; /* Format description line */ snprintf(desc_line, sizeof(desc_line), desc_extent_line, size / 512, desc_filename); - pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line); + g_string_append(ext_desc_lines, desc_line); } /* generate descriptor file */ - snprintf(desc, sizeof(desc), desc_template, - (unsigned int)time(NULL), - parent_cid, - fmt, - parent_desc_line, - ext_desc_lines, - (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), - total_size / (int64_t)(63 * number_heads * 512), number_heads, - adapter_type); + desc = g_strdup_printf(desc_template, + (unsigned int)time(NULL), + parent_cid, + fmt, + parent_desc_line, + ext_desc_lines->str, + (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), + total_size / (int64_t)(63 * number_heads * 512), + number_heads, + adapter_type); if (split || flat) { fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, @@ -1767,21 +1777,25 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, 0644); } if (fd < 0) { - return -errno; + ret = -errno; + goto exit; } /* the descriptor offset = 0x200 */ if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) { ret = -errno; - goto exit; + goto close_exit; } ret = qemu_write_full(fd, desc, strlen(desc)); if (ret != strlen(desc)) { ret = -errno; - goto exit; + goto close_exit; } ret = 0; -exit: +close_exit: qemu_close(fd); +exit: + g_free(desc); + g_string_free(ext_desc_lines, true); return ret; } diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 4926645e5e..73941c3e61 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -75,6 +75,11 @@ echo echo "=== Testing monolithicFlat with zeroed_grain ===" IMGOPTS="subformat=monolithicFlat,zeroed_grain=on" _make_test_img 2G +echo +echo "=== Testing big twoGbMaxExtentFlat ===" +IMGOPTS="subformat=twoGbMaxExtentFlat" _make_test_img 1000G +$QEMU_IMG info $TEST_IMG | _filter_testdir | sed -e 's/cid: [0-9]*/cid: XXXXXXXX/' + echo echo "=== Testing version 3 ===" _use_sample_img iotest-version3.vmdk.bz2 diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 0aadd569d0..4ff935c6f4 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -26,6 +26,2018 @@ virtual size: 2.0G (2147483648 bytes) qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 +=== Testing big twoGbMaxExtentFlat === +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 +image: TEST_DIR/t.vmdk +file format: vmdk +virtual size: 1.0T (1073741824000 bytes) +disk size: 16K +Format specific information: + cid: XXXXXXXX + parent cid: XXXXXXXX + create type: twoGbMaxExtentFlat + extents: + [0]: + virtual size: 2147483648 + filename: TEST_DIR/t-f001.vmdk + format: FLAT + [1]: + virtual size: 2147483648 + filename: TEST_DIR/t-f002.vmdk + format: FLAT + [2]: + virtual size: 2147483648 + filename: TEST_DIR/t-f003.vmdk + format: FLAT + [3]: + virtual size: 2147483648 + filename: TEST_DIR/t-f004.vmdk + format: FLAT + [4]: + virtual size: 2147483648 + filename: TEST_DIR/t-f005.vmdk + format: FLAT + [5]: + virtual size: 2147483648 + filename: TEST_DIR/t-f006.vmdk + format: FLAT + [6]: + virtual size: 2147483648 + filename: TEST_DIR/t-f007.vmdk + format: FLAT + [7]: + virtual size: 2147483648 + filename: TEST_DIR/t-f008.vmdk + format: FLAT + [8]: + virtual size: 2147483648 + filename: TEST_DIR/t-f009.vmdk + format: FLAT + [9]: + virtual size: 2147483648 + filename: TEST_DIR/t-f010.vmdk + format: FLAT + [10]: + virtual size: 2147483648 + filename: TEST_DIR/t-f011.vmdk + format: FLAT + [11]: + virtual size: 2147483648 + filename: TEST_DIR/t-f012.vmdk + format: FLAT + [12]: + virtual size: 2147483648 + filename: TEST_DIR/t-f013.vmdk + format: FLAT + [13]: + virtual size: 2147483648 + filename: TEST_DIR/t-f014.vmdk + format: FLAT + [14]: + virtual size: 2147483648 + filename: TEST_DIR/t-f015.vmdk + format: FLAT + [15]: + virtual size: 2147483648 + filename: TEST_DIR/t-f016.vmdk + format: FLAT + [16]: + virtual size: 2147483648 + filename: TEST_DIR/t-f017.vmdk + format: FLAT + [17]: + virtual size: 2147483648 + filename: TEST_DIR/t-f018.vmdk + format: FLAT + [18]: + virtual size: 2147483648 + filename: TEST_DIR/t-f019.vmdk + format: FLAT + [19]: + virtual size: 2147483648 + filename: TEST_DIR/t-f020.vmdk + format: FLAT + [20]: + virtual size: 2147483648 + filename: TEST_DIR/t-f021.vmdk + format: FLAT + [21]: + virtual size: 2147483648 + filename: TEST_DIR/t-f022.vmdk + format: FLAT + [22]: + virtual size: 2147483648 + filename: TEST_DIR/t-f023.vmdk + format: FLAT + [23]: + virtual size: 2147483648 + filename: TEST_DIR/t-f024.vmdk + format: FLAT + [24]: + virtual size: 2147483648 + filename: TEST_DIR/t-f025.vmdk + format: FLAT + [25]: + virtual size: 2147483648 + filename: TEST_DIR/t-f026.vmdk + format: FLAT + [26]: + virtual size: 2147483648 + filename: TEST_DIR/t-f027.vmdk + format: FLAT + [27]: + virtual size: 2147483648 + filename: TEST_DIR/t-f028.vmdk + format: FLAT + [28]: + virtual size: 2147483648 + filename: TEST_DIR/t-f029.vmdk + format: FLAT + [29]: + virtual size: 2147483648 + filename: TEST_DIR/t-f030.vmdk + format: FLAT + [30]: + virtual size: 2147483648 + filename: TEST_DIR/t-f031.vmdk + format: FLAT + [31]: + virtual size: 2147483648 + filename: TEST_DIR/t-f032.vmdk + format: FLAT + [32]: + virtual size: 2147483648 + filename: TEST_DIR/t-f033.vmdk + format: FLAT + [33]: + virtual size: 2147483648 + filename: TEST_DIR/t-f034.vmdk + format: FLAT + [34]: + virtual size: 2147483648 + filename: TEST_DIR/t-f035.vmdk + format: FLAT + [35]: + virtual size: 2147483648 + filename: TEST_DIR/t-f036.vmdk + format: FLAT + [36]: + virtual size: 2147483648 + filename: TEST_DIR/t-f037.vmdk + format: FLAT + [37]: + virtual size: 2147483648 + filename: TEST_DIR/t-f038.vmdk + format: FLAT + [38]: + virtual size: 2147483648 + filename: TEST_DIR/t-f039.vmdk + format: FLAT + [39]: + virtual size: 2147483648 + filename: TEST_DIR/t-f040.vmdk + format: FLAT + [40]: + virtual size: 2147483648 + filename: TEST_DIR/t-f041.vmdk + format: FLAT + [41]: + virtual size: 2147483648 + filename: TEST_DIR/t-f042.vmdk + format: FLAT + [42]: + virtual size: 2147483648 + filename: TEST_DIR/t-f043.vmdk + format: FLAT + [43]: + virtual size: 2147483648 + filename: TEST_DIR/t-f044.vmdk + format: FLAT + [44]: + virtual size: 2147483648 + filename: TEST_DIR/t-f045.vmdk + format: FLAT + [45]: + virtual size: 2147483648 + filename: TEST_DIR/t-f046.vmdk + format: FLAT + [46]: + virtual size: 2147483648 + filename: TEST_DIR/t-f047.vmdk + format: FLAT + [47]: + virtual size: 2147483648 + filename: TEST_DIR/t-f048.vmdk + format: FLAT + [48]: + virtual size: 2147483648 + filename: TEST_DIR/t-f049.vmdk + format: FLAT + [49]: + virtual size: 2147483648 + filename: TEST_DIR/t-f050.vmdk + format: FLAT + [50]: + virtual size: 2147483648 + filename: TEST_DIR/t-f051.vmdk + format: FLAT + [51]: + virtual size: 2147483648 + filename: TEST_DIR/t-f052.vmdk + format: FLAT + [52]: + virtual size: 2147483648 + filename: TEST_DIR/t-f053.vmdk + format: FLAT + [53]: + virtual size: 2147483648 + filename: TEST_DIR/t-f054.vmdk + format: FLAT + [54]: + virtual size: 2147483648 + filename: TEST_DIR/t-f055.vmdk + format: FLAT + [55]: + virtual size: 2147483648 + filename: TEST_DIR/t-f056.vmdk + format: FLAT + [56]: + virtual size: 2147483648 + filename: TEST_DIR/t-f057.vmdk + format: FLAT + [57]: + virtual size: 2147483648 + filename: TEST_DIR/t-f058.vmdk + format: FLAT + [58]: + virtual size: 2147483648 + filename: TEST_DIR/t-f059.vmdk + format: FLAT + [59]: + virtual size: 2147483648 + filename: TEST_DIR/t-f060.vmdk + format: FLAT + [60]: + virtual size: 2147483648 + filename: TEST_DIR/t-f061.vmdk + format: FLAT + [61]: + virtual size: 2147483648 + filename: TEST_DIR/t-f062.vmdk + format: FLAT + [62]: + virtual size: 2147483648 + filename: TEST_DIR/t-f063.vmdk + format: FLAT + [63]: + virtual size: 2147483648 + filename: TEST_DIR/t-f064.vmdk + format: FLAT + [64]: + virtual size: 2147483648 + filename: TEST_DIR/t-f065.vmdk + format: FLAT + [65]: + virtual size: 2147483648 + filename: TEST_DIR/t-f066.vmdk + format: FLAT + [66]: + virtual size: 2147483648 + filename: TEST_DIR/t-f067.vmdk + format: FLAT + [67]: + virtual size: 2147483648 + filename: TEST_DIR/t-f068.vmdk + format: FLAT + [68]: + virtual size: 2147483648 + filename: TEST_DIR/t-f069.vmdk + format: FLAT + [69]: + virtual size: 2147483648 + filename: TEST_DIR/t-f070.vmdk + format: FLAT + [70]: + virtual size: 2147483648 + filename: TEST_DIR/t-f071.vmdk + format: FLAT + [71]: + virtual size: 2147483648 + filename: TEST_DIR/t-f072.vmdk + format: FLAT + [72]: + virtual size: 2147483648 + filename: TEST_DIR/t-f073.vmdk + format: FLAT + [73]: + virtual size: 2147483648 + filename: TEST_DIR/t-f074.vmdk + format: FLAT + [74]: + virtual size: 2147483648 + filename: TEST_DIR/t-f075.vmdk + format: FLAT + [75]: + virtual size: 2147483648 + filename: TEST_DIR/t-f076.vmdk + format: FLAT + [76]: + virtual size: 2147483648 + filename: TEST_DIR/t-f077.vmdk + format: FLAT + [77]: + virtual size: 2147483648 + filename: TEST_DIR/t-f078.vmdk + format: FLAT + [78]: + virtual size: 2147483648 + filename: TEST_DIR/t-f079.vmdk + format: FLAT + [79]: + virtual size: 2147483648 + filename: TEST_DIR/t-f080.vmdk + format: FLAT + [80]: + virtual size: 2147483648 + filename: TEST_DIR/t-f081.vmdk + format: FLAT + [81]: + virtual size: 2147483648 + filename: TEST_DIR/t-f082.vmdk + format: FLAT + [82]: + virtual size: 2147483648 + filename: TEST_DIR/t-f083.vmdk + format: FLAT + [83]: + virtual size: 2147483648 + filename: TEST_DIR/t-f084.vmdk + format: FLAT + [84]: + virtual size: 2147483648 + filename: TEST_DIR/t-f085.vmdk + format: FLAT + [85]: + virtual size: 2147483648 + filename: TEST_DIR/t-f086.vmdk + format: FLAT + [86]: + virtual size: 2147483648 + filename: TEST_DIR/t-f087.vmdk + format: FLAT + [87]: + virtual size: 2147483648 + filename: TEST_DIR/t-f088.vmdk + format: FLAT + [88]: + virtual size: 2147483648 + filename: TEST_DIR/t-f089.vmdk + format: FLAT + [89]: + virtual size: 2147483648 + filename: TEST_DIR/t-f090.vmdk + format: FLAT + [90]: + virtual size: 2147483648 + filename: TEST_DIR/t-f091.vmdk + format: FLAT + [91]: + virtual size: 2147483648 + filename: TEST_DIR/t-f092.vmdk + format: FLAT + [92]: + virtual size: 2147483648 + filename: TEST_DIR/t-f093.vmdk + format: FLAT + [93]: + virtual size: 2147483648 + filename: TEST_DIR/t-f094.vmdk + format: FLAT + [94]: + virtual size: 2147483648 + filename: TEST_DIR/t-f095.vmdk + format: FLAT + [95]: + virtual size: 2147483648 + filename: TEST_DIR/t-f096.vmdk + format: FLAT + [96]: + virtual size: 2147483648 + filename: TEST_DIR/t-f097.vmdk + format: FLAT + [97]: + virtual size: 2147483648 + filename: TEST_DIR/t-f098.vmdk + format: FLAT + [98]: + virtual size: 2147483648 + filename: TEST_DIR/t-f099.vmdk + format: FLAT + [99]: + virtual size: 2147483648 + filename: TEST_DIR/t-f100.vmdk + format: FLAT + [100]: + virtual size: 2147483648 + filename: TEST_DIR/t-f101.vmdk + format: FLAT + [101]: + virtual size: 2147483648 + filename: TEST_DIR/t-f102.vmdk + format: FLAT + [102]: + virtual size: 2147483648 + filename: TEST_DIR/t-f103.vmdk + format: FLAT + [103]: + virtual size: 2147483648 + filename: TEST_DIR/t-f104.vmdk + format: FLAT + [104]: + virtual size: 2147483648 + filename: TEST_DIR/t-f105.vmdk + format: FLAT + [105]: + virtual size: 2147483648 + filename: TEST_DIR/t-f106.vmdk + format: FLAT + [106]: + virtual size: 2147483648 + filename: TEST_DIR/t-f107.vmdk + format: FLAT + [107]: + virtual size: 2147483648 + filename: TEST_DIR/t-f108.vmdk + format: FLAT + [108]: + virtual size: 2147483648 + filename: TEST_DIR/t-f109.vmdk + format: FLAT + [109]: + virtual size: 2147483648 + filename: TEST_DIR/t-f110.vmdk + format: FLAT + [110]: + virtual size: 2147483648 + filename: TEST_DIR/t-f111.vmdk + format: FLAT + [111]: + virtual size: 2147483648 + filename: TEST_DIR/t-f112.vmdk + format: FLAT + [112]: + virtual size: 2147483648 + filename: TEST_DIR/t-f113.vmdk + format: FLAT + [113]: + virtual size: 2147483648 + filename: TEST_DIR/t-f114.vmdk + format: FLAT + [114]: + virtual size: 2147483648 + filename: TEST_DIR/t-f115.vmdk + format: FLAT + [115]: + virtual size: 2147483648 + filename: TEST_DIR/t-f116.vmdk + format: FLAT + [116]: + virtual size: 2147483648 + filename: TEST_DIR/t-f117.vmdk + format: FLAT + [117]: + virtual size: 2147483648 + filename: TEST_DIR/t-f118.vmdk + format: FLAT + [118]: + virtual size: 2147483648 + filename: TEST_DIR/t-f119.vmdk + format: FLAT + [119]: + virtual size: 2147483648 + filename: TEST_DIR/t-f120.vmdk + format: FLAT + [120]: + virtual size: 2147483648 + filename: TEST_DIR/t-f121.vmdk + format: FLAT + [121]: + virtual size: 2147483648 + filename: TEST_DIR/t-f122.vmdk + format: FLAT + [122]: + virtual size: 2147483648 + filename: TEST_DIR/t-f123.vmdk + format: FLAT + [123]: + virtual size: 2147483648 + filename: TEST_DIR/t-f124.vmdk + format: FLAT + [124]: + virtual size: 2147483648 + filename: TEST_DIR/t-f125.vmdk + format: FLAT + [125]: + virtual size: 2147483648 + filename: TEST_DIR/t-f126.vmdk + format: FLAT + [126]: + virtual size: 2147483648 + filename: TEST_DIR/t-f127.vmdk + format: FLAT + [127]: + virtual size: 2147483648 + filename: TEST_DIR/t-f128.vmdk + format: FLAT + [128]: + virtual size: 2147483648 + filename: TEST_DIR/t-f129.vmdk + format: FLAT + [129]: + virtual size: 2147483648 + filename: TEST_DIR/t-f130.vmdk + format: FLAT + [130]: + virtual size: 2147483648 + filename: TEST_DIR/t-f131.vmdk + format: FLAT + [131]: + virtual size: 2147483648 + filename: TEST_DIR/t-f132.vmdk + format: FLAT + [132]: + virtual size: 2147483648 + filename: TEST_DIR/t-f133.vmdk + format: FLAT + [133]: + virtual size: 2147483648 + filename: TEST_DIR/t-f134.vmdk + format: FLAT + [134]: + virtual size: 2147483648 + filename: TEST_DIR/t-f135.vmdk + format: FLAT + [135]: + virtual size: 2147483648 + filename: TEST_DIR/t-f136.vmdk + format: FLAT + [136]: + virtual size: 2147483648 + filename: TEST_DIR/t-f137.vmdk + format: FLAT + [137]: + virtual size: 2147483648 + filename: TEST_DIR/t-f138.vmdk + format: FLAT + [138]: + virtual size: 2147483648 + filename: TEST_DIR/t-f139.vmdk + format: FLAT + [139]: + virtual size: 2147483648 + filename: TEST_DIR/t-f140.vmdk + format: FLAT + [140]: + virtual size: 2147483648 + filename: TEST_DIR/t-f141.vmdk + format: FLAT + [141]: + virtual size: 2147483648 + filename: TEST_DIR/t-f142.vmdk + format: FLAT + [142]: + virtual size: 2147483648 + filename: TEST_DIR/t-f143.vmdk + format: FLAT + [143]: + virtual size: 2147483648 + filename: TEST_DIR/t-f144.vmdk + format: FLAT + [144]: + virtual size: 2147483648 + filename: TEST_DIR/t-f145.vmdk + format: FLAT + [145]: + virtual size: 2147483648 + filename: TEST_DIR/t-f146.vmdk + format: FLAT + [146]: + virtual size: 2147483648 + filename: TEST_DIR/t-f147.vmdk + format: FLAT + [147]: + virtual size: 2147483648 + filename: TEST_DIR/t-f148.vmdk + format: FLAT + [148]: + virtual size: 2147483648 + filename: TEST_DIR/t-f149.vmdk + format: FLAT + [149]: + virtual size: 2147483648 + filename: TEST_DIR/t-f150.vmdk + format: FLAT + [150]: + virtual size: 2147483648 + filename: TEST_DIR/t-f151.vmdk + format: FLAT + [151]: + virtual size: 2147483648 + filename: TEST_DIR/t-f152.vmdk + format: FLAT + [152]: + virtual size: 2147483648 + filename: TEST_DIR/t-f153.vmdk + format: FLAT + [153]: + virtual size: 2147483648 + filename: TEST_DIR/t-f154.vmdk + format: FLAT + [154]: + virtual size: 2147483648 + filename: TEST_DIR/t-f155.vmdk + format: FLAT + [155]: + virtual size: 2147483648 + filename: TEST_DIR/t-f156.vmdk + format: FLAT + [156]: + virtual size: 2147483648 + filename: TEST_DIR/t-f157.vmdk + format: FLAT + [157]: + virtual size: 2147483648 + filename: TEST_DIR/t-f158.vmdk + format: FLAT + [158]: + virtual size: 2147483648 + filename: TEST_DIR/t-f159.vmdk + format: FLAT + [159]: + virtual size: 2147483648 + filename: TEST_DIR/t-f160.vmdk + format: FLAT + [160]: + virtual size: 2147483648 + filename: TEST_DIR/t-f161.vmdk + format: FLAT + [161]: + virtual size: 2147483648 + filename: TEST_DIR/t-f162.vmdk + format: FLAT + [162]: + virtual size: 2147483648 + filename: TEST_DIR/t-f163.vmdk + format: FLAT + [163]: + virtual size: 2147483648 + filename: TEST_DIR/t-f164.vmdk + format: FLAT + [164]: + virtual size: 2147483648 + filename: TEST_DIR/t-f165.vmdk + format: FLAT + [165]: + virtual size: 2147483648 + filename: TEST_DIR/t-f166.vmdk + format: FLAT + [166]: + virtual size: 2147483648 + filename: TEST_DIR/t-f167.vmdk + format: FLAT + [167]: + virtual size: 2147483648 + filename: TEST_DIR/t-f168.vmdk + format: FLAT + [168]: + virtual size: 2147483648 + filename: TEST_DIR/t-f169.vmdk + format: FLAT + [169]: + virtual size: 2147483648 + filename: TEST_DIR/t-f170.vmdk + format: FLAT + [170]: + virtual size: 2147483648 + filename: TEST_DIR/t-f171.vmdk + format: FLAT + [171]: + virtual size: 2147483648 + filename: TEST_DIR/t-f172.vmdk + format: FLAT + [172]: + virtual size: 2147483648 + filename: TEST_DIR/t-f173.vmdk + format: FLAT + [173]: + virtual size: 2147483648 + filename: TEST_DIR/t-f174.vmdk + format: FLAT + [174]: + virtual size: 2147483648 + filename: TEST_DIR/t-f175.vmdk + format: FLAT + [175]: + virtual size: 2147483648 + filename: TEST_DIR/t-f176.vmdk + format: FLAT + [176]: + virtual size: 2147483648 + filename: TEST_DIR/t-f177.vmdk + format: FLAT + [177]: + virtual size: 2147483648 + filename: TEST_DIR/t-f178.vmdk + format: FLAT + [178]: + virtual size: 2147483648 + filename: TEST_DIR/t-f179.vmdk + format: FLAT + [179]: + virtual size: 2147483648 + filename: TEST_DIR/t-f180.vmdk + format: FLAT + [180]: + virtual size: 2147483648 + filename: TEST_DIR/t-f181.vmdk + format: FLAT + [181]: + virtual size: 2147483648 + filename: TEST_DIR/t-f182.vmdk + format: FLAT + [182]: + virtual size: 2147483648 + filename: TEST_DIR/t-f183.vmdk + format: FLAT + [183]: + virtual size: 2147483648 + filename: TEST_DIR/t-f184.vmdk + format: FLAT + [184]: + virtual size: 2147483648 + filename: TEST_DIR/t-f185.vmdk + format: FLAT + [185]: + virtual size: 2147483648 + filename: TEST_DIR/t-f186.vmdk + format: FLAT + [186]: + virtual size: 2147483648 + filename: TEST_DIR/t-f187.vmdk + format: FLAT + [187]: + virtual size: 2147483648 + filename: TEST_DIR/t-f188.vmdk + format: FLAT + [188]: + virtual size: 2147483648 + filename: TEST_DIR/t-f189.vmdk + format: FLAT + [189]: + virtual size: 2147483648 + filename: TEST_DIR/t-f190.vmdk + format: FLAT + [190]: + virtual size: 2147483648 + filename: TEST_DIR/t-f191.vmdk + format: FLAT + [191]: + virtual size: 2147483648 + filename: TEST_DIR/t-f192.vmdk + format: FLAT + [192]: + virtual size: 2147483648 + filename: TEST_DIR/t-f193.vmdk + format: FLAT + [193]: + virtual size: 2147483648 + filename: TEST_DIR/t-f194.vmdk + format: FLAT + [194]: + virtual size: 2147483648 + filename: TEST_DIR/t-f195.vmdk + format: FLAT + [195]: + virtual size: 2147483648 + filename: TEST_DIR/t-f196.vmdk + format: FLAT + [196]: + virtual size: 2147483648 + filename: TEST_DIR/t-f197.vmdk + format: FLAT + [197]: + virtual size: 2147483648 + filename: TEST_DIR/t-f198.vmdk + format: FLAT + [198]: + virtual size: 2147483648 + filename: TEST_DIR/t-f199.vmdk + format: FLAT + [199]: + virtual size: 2147483648 + filename: TEST_DIR/t-f200.vmdk + format: FLAT + [200]: + virtual size: 2147483648 + filename: TEST_DIR/t-f201.vmdk + format: FLAT + [201]: + virtual size: 2147483648 + filename: TEST_DIR/t-f202.vmdk + format: FLAT + [202]: + virtual size: 2147483648 + filename: TEST_DIR/t-f203.vmdk + format: FLAT + [203]: + virtual size: 2147483648 + filename: TEST_DIR/t-f204.vmdk + format: FLAT + [204]: + virtual size: 2147483648 + filename: TEST_DIR/t-f205.vmdk + format: FLAT + [205]: + virtual size: 2147483648 + filename: TEST_DIR/t-f206.vmdk + format: FLAT + [206]: + virtual size: 2147483648 + filename: TEST_DIR/t-f207.vmdk + format: FLAT + [207]: + virtual size: 2147483648 + filename: TEST_DIR/t-f208.vmdk + format: FLAT + [208]: + virtual size: 2147483648 + filename: TEST_DIR/t-f209.vmdk + format: FLAT + [209]: + virtual size: 2147483648 + filename: TEST_DIR/t-f210.vmdk + format: FLAT + [210]: + virtual size: 2147483648 + filename: TEST_DIR/t-f211.vmdk + format: FLAT + [211]: + virtual size: 2147483648 + filename: TEST_DIR/t-f212.vmdk + format: FLAT + [212]: + virtual size: 2147483648 + filename: TEST_DIR/t-f213.vmdk + format: FLAT + [213]: + virtual size: 2147483648 + filename: TEST_DIR/t-f214.vmdk + format: FLAT + [214]: + virtual size: 2147483648 + filename: TEST_DIR/t-f215.vmdk + format: FLAT + [215]: + virtual size: 2147483648 + filename: TEST_DIR/t-f216.vmdk + format: FLAT + [216]: + virtual size: 2147483648 + filename: TEST_DIR/t-f217.vmdk + format: FLAT + [217]: + virtual size: 2147483648 + filename: TEST_DIR/t-f218.vmdk + format: FLAT + [218]: + virtual size: 2147483648 + filename: TEST_DIR/t-f219.vmdk + format: FLAT + [219]: + virtual size: 2147483648 + filename: TEST_DIR/t-f220.vmdk + format: FLAT + [220]: + virtual size: 2147483648 + filename: TEST_DIR/t-f221.vmdk + format: FLAT + [221]: + virtual size: 2147483648 + filename: TEST_DIR/t-f222.vmdk + format: FLAT + [222]: + virtual size: 2147483648 + filename: TEST_DIR/t-f223.vmdk + format: FLAT + [223]: + virtual size: 2147483648 + filename: TEST_DIR/t-f224.vmdk + format: FLAT + [224]: + virtual size: 2147483648 + filename: TEST_DIR/t-f225.vmdk + format: FLAT + [225]: + virtual size: 2147483648 + filename: TEST_DIR/t-f226.vmdk + format: FLAT + [226]: + virtual size: 2147483648 + filename: TEST_DIR/t-f227.vmdk + format: FLAT + [227]: + virtual size: 2147483648 + filename: TEST_DIR/t-f228.vmdk + format: FLAT + [228]: + virtual size: 2147483648 + filename: TEST_DIR/t-f229.vmdk + format: FLAT + [229]: + virtual size: 2147483648 + filename: TEST_DIR/t-f230.vmdk + format: FLAT + [230]: + virtual size: 2147483648 + filename: TEST_DIR/t-f231.vmdk + format: FLAT + [231]: + virtual size: 2147483648 + filename: TEST_DIR/t-f232.vmdk + format: FLAT + [232]: + virtual size: 2147483648 + filename: TEST_DIR/t-f233.vmdk + format: FLAT + [233]: + virtual size: 2147483648 + filename: TEST_DIR/t-f234.vmdk + format: FLAT + [234]: + virtual size: 2147483648 + filename: TEST_DIR/t-f235.vmdk + format: FLAT + [235]: + virtual size: 2147483648 + filename: TEST_DIR/t-f236.vmdk + format: FLAT + [236]: + virtual size: 2147483648 + filename: TEST_DIR/t-f237.vmdk + format: FLAT + [237]: + virtual size: 2147483648 + filename: TEST_DIR/t-f238.vmdk + format: FLAT + [238]: + virtual size: 2147483648 + filename: TEST_DIR/t-f239.vmdk + format: FLAT + [239]: + virtual size: 2147483648 + filename: TEST_DIR/t-f240.vmdk + format: FLAT + [240]: + virtual size: 2147483648 + filename: TEST_DIR/t-f241.vmdk + format: FLAT + [241]: + virtual size: 2147483648 + filename: TEST_DIR/t-f242.vmdk + format: FLAT + [242]: + virtual size: 2147483648 + filename: TEST_DIR/t-f243.vmdk + format: FLAT + [243]: + virtual size: 2147483648 + filename: TEST_DIR/t-f244.vmdk + format: FLAT + [244]: + virtual size: 2147483648 + filename: TEST_DIR/t-f245.vmdk + format: FLAT + [245]: + virtual size: 2147483648 + filename: TEST_DIR/t-f246.vmdk + format: FLAT + [246]: + virtual size: 2147483648 + filename: TEST_DIR/t-f247.vmdk + format: FLAT + [247]: + virtual size: 2147483648 + filename: TEST_DIR/t-f248.vmdk + format: FLAT + [248]: + virtual size: 2147483648 + filename: TEST_DIR/t-f249.vmdk + format: FLAT + [249]: + virtual size: 2147483648 + filename: TEST_DIR/t-f250.vmdk + format: FLAT + [250]: + virtual size: 2147483648 + filename: TEST_DIR/t-f251.vmdk + format: FLAT + [251]: + virtual size: 2147483648 + filename: TEST_DIR/t-f252.vmdk + format: FLAT + [252]: + virtual size: 2147483648 + filename: TEST_DIR/t-f253.vmdk + format: FLAT + [253]: + virtual size: 2147483648 + filename: TEST_DIR/t-f254.vmdk + format: FLAT + [254]: + virtual size: 2147483648 + filename: TEST_DIR/t-f255.vmdk + format: FLAT + [255]: + virtual size: 2147483648 + filename: TEST_DIR/t-f256.vmdk + format: FLAT + [256]: + virtual size: 2147483648 + filename: TEST_DIR/t-f257.vmdk + format: FLAT + [257]: + virtual size: 2147483648 + filename: TEST_DIR/t-f258.vmdk + format: FLAT + [258]: + virtual size: 2147483648 + filename: TEST_DIR/t-f259.vmdk + format: FLAT + [259]: + virtual size: 2147483648 + filename: TEST_DIR/t-f260.vmdk + format: FLAT + [260]: + virtual size: 2147483648 + filename: TEST_DIR/t-f261.vmdk + format: FLAT + [261]: + virtual size: 2147483648 + filename: TEST_DIR/t-f262.vmdk + format: FLAT + [262]: + virtual size: 2147483648 + filename: TEST_DIR/t-f263.vmdk + format: FLAT + [263]: + virtual size: 2147483648 + filename: TEST_DIR/t-f264.vmdk + format: FLAT + [264]: + virtual size: 2147483648 + filename: TEST_DIR/t-f265.vmdk + format: FLAT + [265]: + virtual size: 2147483648 + filename: TEST_DIR/t-f266.vmdk + format: FLAT + [266]: + virtual size: 2147483648 + filename: TEST_DIR/t-f267.vmdk + format: FLAT + [267]: + virtual size: 2147483648 + filename: TEST_DIR/t-f268.vmdk + format: FLAT + [268]: + virtual size: 2147483648 + filename: TEST_DIR/t-f269.vmdk + format: FLAT + [269]: + virtual size: 2147483648 + filename: TEST_DIR/t-f270.vmdk + format: FLAT + [270]: + virtual size: 2147483648 + filename: TEST_DIR/t-f271.vmdk + format: FLAT + [271]: + virtual size: 2147483648 + filename: TEST_DIR/t-f272.vmdk + format: FLAT + [272]: + virtual size: 2147483648 + filename: TEST_DIR/t-f273.vmdk + format: FLAT + [273]: + virtual size: 2147483648 + filename: TEST_DIR/t-f274.vmdk + format: FLAT + [274]: + virtual size: 2147483648 + filename: TEST_DIR/t-f275.vmdk + format: FLAT + [275]: + virtual size: 2147483648 + filename: TEST_DIR/t-f276.vmdk + format: FLAT + [276]: + virtual size: 2147483648 + filename: TEST_DIR/t-f277.vmdk + format: FLAT + [277]: + virtual size: 2147483648 + filename: TEST_DIR/t-f278.vmdk + format: FLAT + [278]: + virtual size: 2147483648 + filename: TEST_DIR/t-f279.vmdk + format: FLAT + [279]: + virtual size: 2147483648 + filename: TEST_DIR/t-f280.vmdk + format: FLAT + [280]: + virtual size: 2147483648 + filename: TEST_DIR/t-f281.vmdk + format: FLAT + [281]: + virtual size: 2147483648 + filename: TEST_DIR/t-f282.vmdk + format: FLAT + [282]: + virtual size: 2147483648 + filename: TEST_DIR/t-f283.vmdk + format: FLAT + [283]: + virtual size: 2147483648 + filename: TEST_DIR/t-f284.vmdk + format: FLAT + [284]: + virtual size: 2147483648 + filename: TEST_DIR/t-f285.vmdk + format: FLAT + [285]: + virtual size: 2147483648 + filename: TEST_DIR/t-f286.vmdk + format: FLAT + [286]: + virtual size: 2147483648 + filename: TEST_DIR/t-f287.vmdk + format: FLAT + [287]: + virtual size: 2147483648 + filename: TEST_DIR/t-f288.vmdk + format: FLAT + [288]: + virtual size: 2147483648 + filename: TEST_DIR/t-f289.vmdk + format: FLAT + [289]: + virtual size: 2147483648 + filename: TEST_DIR/t-f290.vmdk + format: FLAT + [290]: + virtual size: 2147483648 + filename: TEST_DIR/t-f291.vmdk + format: FLAT + [291]: + virtual size: 2147483648 + filename: TEST_DIR/t-f292.vmdk + format: FLAT + [292]: + virtual size: 2147483648 + filename: TEST_DIR/t-f293.vmdk + format: FLAT + [293]: + virtual size: 2147483648 + filename: TEST_DIR/t-f294.vmdk + format: FLAT + [294]: + virtual size: 2147483648 + filename: TEST_DIR/t-f295.vmdk + format: FLAT + [295]: + virtual size: 2147483648 + filename: TEST_DIR/t-f296.vmdk + format: FLAT + [296]: + virtual size: 2147483648 + filename: TEST_DIR/t-f297.vmdk + format: FLAT + [297]: + virtual size: 2147483648 + filename: TEST_DIR/t-f298.vmdk + format: FLAT + [298]: + virtual size: 2147483648 + filename: TEST_DIR/t-f299.vmdk + format: FLAT + [299]: + virtual size: 2147483648 + filename: TEST_DIR/t-f300.vmdk + format: FLAT + [300]: + virtual size: 2147483648 + filename: TEST_DIR/t-f301.vmdk + format: FLAT + [301]: + virtual size: 2147483648 + filename: TEST_DIR/t-f302.vmdk + format: FLAT + [302]: + virtual size: 2147483648 + filename: TEST_DIR/t-f303.vmdk + format: FLAT + [303]: + virtual size: 2147483648 + filename: TEST_DIR/t-f304.vmdk + format: FLAT + [304]: + virtual size: 2147483648 + filename: TEST_DIR/t-f305.vmdk + format: FLAT + [305]: + virtual size: 2147483648 + filename: TEST_DIR/t-f306.vmdk + format: FLAT + [306]: + virtual size: 2147483648 + filename: TEST_DIR/t-f307.vmdk + format: FLAT + [307]: + virtual size: 2147483648 + filename: TEST_DIR/t-f308.vmdk + format: FLAT + [308]: + virtual size: 2147483648 + filename: TEST_DIR/t-f309.vmdk + format: FLAT + [309]: + virtual size: 2147483648 + filename: TEST_DIR/t-f310.vmdk + format: FLAT + [310]: + virtual size: 2147483648 + filename: TEST_DIR/t-f311.vmdk + format: FLAT + [311]: + virtual size: 2147483648 + filename: TEST_DIR/t-f312.vmdk + format: FLAT + [312]: + virtual size: 2147483648 + filename: TEST_DIR/t-f313.vmdk + format: FLAT + [313]: + virtual size: 2147483648 + filename: TEST_DIR/t-f314.vmdk + format: FLAT + [314]: + virtual size: 2147483648 + filename: TEST_DIR/t-f315.vmdk + format: FLAT + [315]: + virtual size: 2147483648 + filename: TEST_DIR/t-f316.vmdk + format: FLAT + [316]: + virtual size: 2147483648 + filename: TEST_DIR/t-f317.vmdk + format: FLAT + [317]: + virtual size: 2147483648 + filename: TEST_DIR/t-f318.vmdk + format: FLAT + [318]: + virtual size: 2147483648 + filename: TEST_DIR/t-f319.vmdk + format: FLAT + [319]: + virtual size: 2147483648 + filename: TEST_DIR/t-f320.vmdk + format: FLAT + [320]: + virtual size: 2147483648 + filename: TEST_DIR/t-f321.vmdk + format: FLAT + [321]: + virtual size: 2147483648 + filename: TEST_DIR/t-f322.vmdk + format: FLAT + [322]: + virtual size: 2147483648 + filename: TEST_DIR/t-f323.vmdk + format: FLAT + [323]: + virtual size: 2147483648 + filename: TEST_DIR/t-f324.vmdk + format: FLAT + [324]: + virtual size: 2147483648 + filename: TEST_DIR/t-f325.vmdk + format: FLAT + [325]: + virtual size: 2147483648 + filename: TEST_DIR/t-f326.vmdk + format: FLAT + [326]: + virtual size: 2147483648 + filename: TEST_DIR/t-f327.vmdk + format: FLAT + [327]: + virtual size: 2147483648 + filename: TEST_DIR/t-f328.vmdk + format: FLAT + [328]: + virtual size: 2147483648 + filename: TEST_DIR/t-f329.vmdk + format: FLAT + [329]: + virtual size: 2147483648 + filename: TEST_DIR/t-f330.vmdk + format: FLAT + [330]: + virtual size: 2147483648 + filename: TEST_DIR/t-f331.vmdk + format: FLAT + [331]: + virtual size: 2147483648 + filename: TEST_DIR/t-f332.vmdk + format: FLAT + [332]: + virtual size: 2147483648 + filename: TEST_DIR/t-f333.vmdk + format: FLAT + [333]: + virtual size: 2147483648 + filename: TEST_DIR/t-f334.vmdk + format: FLAT + [334]: + virtual size: 2147483648 + filename: TEST_DIR/t-f335.vmdk + format: FLAT + [335]: + virtual size: 2147483648 + filename: TEST_DIR/t-f336.vmdk + format: FLAT + [336]: + virtual size: 2147483648 + filename: TEST_DIR/t-f337.vmdk + format: FLAT + [337]: + virtual size: 2147483648 + filename: TEST_DIR/t-f338.vmdk + format: FLAT + [338]: + virtual size: 2147483648 + filename: TEST_DIR/t-f339.vmdk + format: FLAT + [339]: + virtual size: 2147483648 + filename: TEST_DIR/t-f340.vmdk + format: FLAT + [340]: + virtual size: 2147483648 + filename: TEST_DIR/t-f341.vmdk + format: FLAT + [341]: + virtual size: 2147483648 + filename: TEST_DIR/t-f342.vmdk + format: FLAT + [342]: + virtual size: 2147483648 + filename: TEST_DIR/t-f343.vmdk + format: FLAT + [343]: + virtual size: 2147483648 + filename: TEST_DIR/t-f344.vmdk + format: FLAT + [344]: + virtual size: 2147483648 + filename: TEST_DIR/t-f345.vmdk + format: FLAT + [345]: + virtual size: 2147483648 + filename: TEST_DIR/t-f346.vmdk + format: FLAT + [346]: + virtual size: 2147483648 + filename: TEST_DIR/t-f347.vmdk + format: FLAT + [347]: + virtual size: 2147483648 + filename: TEST_DIR/t-f348.vmdk + format: FLAT + [348]: + virtual size: 2147483648 + filename: TEST_DIR/t-f349.vmdk + format: FLAT + [349]: + virtual size: 2147483648 + filename: TEST_DIR/t-f350.vmdk + format: FLAT + [350]: + virtual size: 2147483648 + filename: TEST_DIR/t-f351.vmdk + format: FLAT + [351]: + virtual size: 2147483648 + filename: TEST_DIR/t-f352.vmdk + format: FLAT + [352]: + virtual size: 2147483648 + filename: TEST_DIR/t-f353.vmdk + format: FLAT + [353]: + virtual size: 2147483648 + filename: TEST_DIR/t-f354.vmdk + format: FLAT + [354]: + virtual size: 2147483648 + filename: TEST_DIR/t-f355.vmdk + format: FLAT + [355]: + virtual size: 2147483648 + filename: TEST_DIR/t-f356.vmdk + format: FLAT + [356]: + virtual size: 2147483648 + filename: TEST_DIR/t-f357.vmdk + format: FLAT + [357]: + virtual size: 2147483648 + filename: TEST_DIR/t-f358.vmdk + format: FLAT + [358]: + virtual size: 2147483648 + filename: TEST_DIR/t-f359.vmdk + format: FLAT + [359]: + virtual size: 2147483648 + filename: TEST_DIR/t-f360.vmdk + format: FLAT + [360]: + virtual size: 2147483648 + filename: TEST_DIR/t-f361.vmdk + format: FLAT + [361]: + virtual size: 2147483648 + filename: TEST_DIR/t-f362.vmdk + format: FLAT + [362]: + virtual size: 2147483648 + filename: TEST_DIR/t-f363.vmdk + format: FLAT + [363]: + virtual size: 2147483648 + filename: TEST_DIR/t-f364.vmdk + format: FLAT + [364]: + virtual size: 2147483648 + filename: TEST_DIR/t-f365.vmdk + format: FLAT + [365]: + virtual size: 2147483648 + filename: TEST_DIR/t-f366.vmdk + format: FLAT + [366]: + virtual size: 2147483648 + filename: TEST_DIR/t-f367.vmdk + format: FLAT + [367]: + virtual size: 2147483648 + filename: TEST_DIR/t-f368.vmdk + format: FLAT + [368]: + virtual size: 2147483648 + filename: TEST_DIR/t-f369.vmdk + format: FLAT + [369]: + virtual size: 2147483648 + filename: TEST_DIR/t-f370.vmdk + format: FLAT + [370]: + virtual size: 2147483648 + filename: TEST_DIR/t-f371.vmdk + format: FLAT + [371]: + virtual size: 2147483648 + filename: TEST_DIR/t-f372.vmdk + format: FLAT + [372]: + virtual size: 2147483648 + filename: TEST_DIR/t-f373.vmdk + format: FLAT + [373]: + virtual size: 2147483648 + filename: TEST_DIR/t-f374.vmdk + format: FLAT + [374]: + virtual size: 2147483648 + filename: TEST_DIR/t-f375.vmdk + format: FLAT + [375]: + virtual size: 2147483648 + filename: TEST_DIR/t-f376.vmdk + format: FLAT + [376]: + virtual size: 2147483648 + filename: TEST_DIR/t-f377.vmdk + format: FLAT + [377]: + virtual size: 2147483648 + filename: TEST_DIR/t-f378.vmdk + format: FLAT + [378]: + virtual size: 2147483648 + filename: TEST_DIR/t-f379.vmdk + format: FLAT + [379]: + virtual size: 2147483648 + filename: TEST_DIR/t-f380.vmdk + format: FLAT + [380]: + virtual size: 2147483648 + filename: TEST_DIR/t-f381.vmdk + format: FLAT + [381]: + virtual size: 2147483648 + filename: TEST_DIR/t-f382.vmdk + format: FLAT + [382]: + virtual size: 2147483648 + filename: TEST_DIR/t-f383.vmdk + format: FLAT + [383]: + virtual size: 2147483648 + filename: TEST_DIR/t-f384.vmdk + format: FLAT + [384]: + virtual size: 2147483648 + filename: TEST_DIR/t-f385.vmdk + format: FLAT + [385]: + virtual size: 2147483648 + filename: TEST_DIR/t-f386.vmdk + format: FLAT + [386]: + virtual size: 2147483648 + filename: TEST_DIR/t-f387.vmdk + format: FLAT + [387]: + virtual size: 2147483648 + filename: TEST_DIR/t-f388.vmdk + format: FLAT + [388]: + virtual size: 2147483648 + filename: TEST_DIR/t-f389.vmdk + format: FLAT + [389]: + virtual size: 2147483648 + filename: TEST_DIR/t-f390.vmdk + format: FLAT + [390]: + virtual size: 2147483648 + filename: TEST_DIR/t-f391.vmdk + format: FLAT + [391]: + virtual size: 2147483648 + filename: TEST_DIR/t-f392.vmdk + format: FLAT + [392]: + virtual size: 2147483648 + filename: TEST_DIR/t-f393.vmdk + format: FLAT + [393]: + virtual size: 2147483648 + filename: TEST_DIR/t-f394.vmdk + format: FLAT + [394]: + virtual size: 2147483648 + filename: TEST_DIR/t-f395.vmdk + format: FLAT + [395]: + virtual size: 2147483648 + filename: TEST_DIR/t-f396.vmdk + format: FLAT + [396]: + virtual size: 2147483648 + filename: TEST_DIR/t-f397.vmdk + format: FLAT + [397]: + virtual size: 2147483648 + filename: TEST_DIR/t-f398.vmdk + format: FLAT + [398]: + virtual size: 2147483648 + filename: TEST_DIR/t-f399.vmdk + format: FLAT + [399]: + virtual size: 2147483648 + filename: TEST_DIR/t-f400.vmdk + format: FLAT + [400]: + virtual size: 2147483648 + filename: TEST_DIR/t-f401.vmdk + format: FLAT + [401]: + virtual size: 2147483648 + filename: TEST_DIR/t-f402.vmdk + format: FLAT + [402]: + virtual size: 2147483648 + filename: TEST_DIR/t-f403.vmdk + format: FLAT + [403]: + virtual size: 2147483648 + filename: TEST_DIR/t-f404.vmdk + format: FLAT + [404]: + virtual size: 2147483648 + filename: TEST_DIR/t-f405.vmdk + format: FLAT + [405]: + virtual size: 2147483648 + filename: TEST_DIR/t-f406.vmdk + format: FLAT + [406]: + virtual size: 2147483648 + filename: TEST_DIR/t-f407.vmdk + format: FLAT + [407]: + virtual size: 2147483648 + filename: TEST_DIR/t-f408.vmdk + format: FLAT + [408]: + virtual size: 2147483648 + filename: TEST_DIR/t-f409.vmdk + format: FLAT + [409]: + virtual size: 2147483648 + filename: TEST_DIR/t-f410.vmdk + format: FLAT + [410]: + virtual size: 2147483648 + filename: TEST_DIR/t-f411.vmdk + format: FLAT + [411]: + virtual size: 2147483648 + filename: TEST_DIR/t-f412.vmdk + format: FLAT + [412]: + virtual size: 2147483648 + filename: TEST_DIR/t-f413.vmdk + format: FLAT + [413]: + virtual size: 2147483648 + filename: TEST_DIR/t-f414.vmdk + format: FLAT + [414]: + virtual size: 2147483648 + filename: TEST_DIR/t-f415.vmdk + format: FLAT + [415]: + virtual size: 2147483648 + filename: TEST_DIR/t-f416.vmdk + format: FLAT + [416]: + virtual size: 2147483648 + filename: TEST_DIR/t-f417.vmdk + format: FLAT + [417]: + virtual size: 2147483648 + filename: TEST_DIR/t-f418.vmdk + format: FLAT + [418]: + virtual size: 2147483648 + filename: TEST_DIR/t-f419.vmdk + format: FLAT + [419]: + virtual size: 2147483648 + filename: TEST_DIR/t-f420.vmdk + format: FLAT + [420]: + virtual size: 2147483648 + filename: TEST_DIR/t-f421.vmdk + format: FLAT + [421]: + virtual size: 2147483648 + filename: TEST_DIR/t-f422.vmdk + format: FLAT + [422]: + virtual size: 2147483648 + filename: TEST_DIR/t-f423.vmdk + format: FLAT + [423]: + virtual size: 2147483648 + filename: TEST_DIR/t-f424.vmdk + format: FLAT + [424]: + virtual size: 2147483648 + filename: TEST_DIR/t-f425.vmdk + format: FLAT + [425]: + virtual size: 2147483648 + filename: TEST_DIR/t-f426.vmdk + format: FLAT + [426]: + virtual size: 2147483648 + filename: TEST_DIR/t-f427.vmdk + format: FLAT + [427]: + virtual size: 2147483648 + filename: TEST_DIR/t-f428.vmdk + format: FLAT + [428]: + virtual size: 2147483648 + filename: TEST_DIR/t-f429.vmdk + format: FLAT + [429]: + virtual size: 2147483648 + filename: TEST_DIR/t-f430.vmdk + format: FLAT + [430]: + virtual size: 2147483648 + filename: TEST_DIR/t-f431.vmdk + format: FLAT + [431]: + virtual size: 2147483648 + filename: TEST_DIR/t-f432.vmdk + format: FLAT + [432]: + virtual size: 2147483648 + filename: TEST_DIR/t-f433.vmdk + format: FLAT + [433]: + virtual size: 2147483648 + filename: TEST_DIR/t-f434.vmdk + format: FLAT + [434]: + virtual size: 2147483648 + filename: TEST_DIR/t-f435.vmdk + format: FLAT + [435]: + virtual size: 2147483648 + filename: TEST_DIR/t-f436.vmdk + format: FLAT + [436]: + virtual size: 2147483648 + filename: TEST_DIR/t-f437.vmdk + format: FLAT + [437]: + virtual size: 2147483648 + filename: TEST_DIR/t-f438.vmdk + format: FLAT + [438]: + virtual size: 2147483648 + filename: TEST_DIR/t-f439.vmdk + format: FLAT + [439]: + virtual size: 2147483648 + filename: TEST_DIR/t-f440.vmdk + format: FLAT + [440]: + virtual size: 2147483648 + filename: TEST_DIR/t-f441.vmdk + format: FLAT + [441]: + virtual size: 2147483648 + filename: TEST_DIR/t-f442.vmdk + format: FLAT + [442]: + virtual size: 2147483648 + filename: TEST_DIR/t-f443.vmdk + format: FLAT + [443]: + virtual size: 2147483648 + filename: TEST_DIR/t-f444.vmdk + format: FLAT + [444]: + virtual size: 2147483648 + filename: TEST_DIR/t-f445.vmdk + format: FLAT + [445]: + virtual size: 2147483648 + filename: TEST_DIR/t-f446.vmdk + format: FLAT + [446]: + virtual size: 2147483648 + filename: TEST_DIR/t-f447.vmdk + format: FLAT + [447]: + virtual size: 2147483648 + filename: TEST_DIR/t-f448.vmdk + format: FLAT + [448]: + virtual size: 2147483648 + filename: TEST_DIR/t-f449.vmdk + format: FLAT + [449]: + virtual size: 2147483648 + filename: TEST_DIR/t-f450.vmdk + format: FLAT + [450]: + virtual size: 2147483648 + filename: TEST_DIR/t-f451.vmdk + format: FLAT + [451]: + virtual size: 2147483648 + filename: TEST_DIR/t-f452.vmdk + format: FLAT + [452]: + virtual size: 2147483648 + filename: TEST_DIR/t-f453.vmdk + format: FLAT + [453]: + virtual size: 2147483648 + filename: TEST_DIR/t-f454.vmdk + format: FLAT + [454]: + virtual size: 2147483648 + filename: TEST_DIR/t-f455.vmdk + format: FLAT + [455]: + virtual size: 2147483648 + filename: TEST_DIR/t-f456.vmdk + format: FLAT + [456]: + virtual size: 2147483648 + filename: TEST_DIR/t-f457.vmdk + format: FLAT + [457]: + virtual size: 2147483648 + filename: TEST_DIR/t-f458.vmdk + format: FLAT + [458]: + virtual size: 2147483648 + filename: TEST_DIR/t-f459.vmdk + format: FLAT + [459]: + virtual size: 2147483648 + filename: TEST_DIR/t-f460.vmdk + format: FLAT + [460]: + virtual size: 2147483648 + filename: TEST_DIR/t-f461.vmdk + format: FLAT + [461]: + virtual size: 2147483648 + filename: TEST_DIR/t-f462.vmdk + format: FLAT + [462]: + virtual size: 2147483648 + filename: TEST_DIR/t-f463.vmdk + format: FLAT + [463]: + virtual size: 2147483648 + filename: TEST_DIR/t-f464.vmdk + format: FLAT + [464]: + virtual size: 2147483648 + filename: TEST_DIR/t-f465.vmdk + format: FLAT + [465]: + virtual size: 2147483648 + filename: TEST_DIR/t-f466.vmdk + format: FLAT + [466]: + virtual size: 2147483648 + filename: TEST_DIR/t-f467.vmdk + format: FLAT + [467]: + virtual size: 2147483648 + filename: TEST_DIR/t-f468.vmdk + format: FLAT + [468]: + virtual size: 2147483648 + filename: TEST_DIR/t-f469.vmdk + format: FLAT + [469]: + virtual size: 2147483648 + filename: TEST_DIR/t-f470.vmdk + format: FLAT + [470]: + virtual size: 2147483648 + filename: TEST_DIR/t-f471.vmdk + format: FLAT + [471]: + virtual size: 2147483648 + filename: TEST_DIR/t-f472.vmdk + format: FLAT + [472]: + virtual size: 2147483648 + filename: TEST_DIR/t-f473.vmdk + format: FLAT + [473]: + virtual size: 2147483648 + filename: TEST_DIR/t-f474.vmdk + format: FLAT + [474]: + virtual size: 2147483648 + filename: TEST_DIR/t-f475.vmdk + format: FLAT + [475]: + virtual size: 2147483648 + filename: TEST_DIR/t-f476.vmdk + format: FLAT + [476]: + virtual size: 2147483648 + filename: TEST_DIR/t-f477.vmdk + format: FLAT + [477]: + virtual size: 2147483648 + filename: TEST_DIR/t-f478.vmdk + format: FLAT + [478]: + virtual size: 2147483648 + filename: TEST_DIR/t-f479.vmdk + format: FLAT + [479]: + virtual size: 2147483648 + filename: TEST_DIR/t-f480.vmdk + format: FLAT + [480]: + virtual size: 2147483648 + filename: TEST_DIR/t-f481.vmdk + format: FLAT + [481]: + virtual size: 2147483648 + filename: TEST_DIR/t-f482.vmdk + format: FLAT + [482]: + virtual size: 2147483648 + filename: TEST_DIR/t-f483.vmdk + format: FLAT + [483]: + virtual size: 2147483648 + filename: TEST_DIR/t-f484.vmdk + format: FLAT + [484]: + virtual size: 2147483648 + filename: TEST_DIR/t-f485.vmdk + format: FLAT + [485]: + virtual size: 2147483648 + filename: TEST_DIR/t-f486.vmdk + format: FLAT + [486]: + virtual size: 2147483648 + filename: TEST_DIR/t-f487.vmdk + format: FLAT + [487]: + virtual size: 2147483648 + filename: TEST_DIR/t-f488.vmdk + format: FLAT + [488]: + virtual size: 2147483648 + filename: TEST_DIR/t-f489.vmdk + format: FLAT + [489]: + virtual size: 2147483648 + filename: TEST_DIR/t-f490.vmdk + format: FLAT + [490]: + virtual size: 2147483648 + filename: TEST_DIR/t-f491.vmdk + format: FLAT + [491]: + virtual size: 2147483648 + filename: TEST_DIR/t-f492.vmdk + format: FLAT + [492]: + virtual size: 2147483648 + filename: TEST_DIR/t-f493.vmdk + format: FLAT + [493]: + virtual size: 2147483648 + filename: TEST_DIR/t-f494.vmdk + format: FLAT + [494]: + virtual size: 2147483648 + filename: TEST_DIR/t-f495.vmdk + format: FLAT + [495]: + virtual size: 2147483648 + filename: TEST_DIR/t-f496.vmdk + format: FLAT + [496]: + virtual size: 2147483648 + filename: TEST_DIR/t-f497.vmdk + format: FLAT + [497]: + virtual size: 2147483648 + filename: TEST_DIR/t-f498.vmdk + format: FLAT + [498]: + virtual size: 2147483648 + filename: TEST_DIR/t-f499.vmdk + format: FLAT + [499]: + virtual size: 2147483648 + filename: TEST_DIR/t-f500.vmdk + format: FLAT + === Testing version 3 === image: TEST_DIR/iotest-version3.IMGFMT file format: IMGFMT From d51e9fe505f7c7b97762100dd0e42cef43c90524 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:43 +0100 Subject: [PATCH 04/48] block: generalize BlockLimits handling to cover bdrv_aio_discard too bdrv_co_discard is only covering drivers which have a .bdrv_co_discard() implementation, but not those with .bdrv_aio_discard(). Not very nice, and easy to avoid. Suggested-by: Kevin Wolf Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block.c | 96 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/block.c b/block.c index 3d78581c63..506518be88 100644 --- a/block.c +++ b/block.c @@ -4302,6 +4302,8 @@ static void coroutine_fn bdrv_discard_co_entry(void *opaque) int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { + int max_discard; + if (!bs->drv) { return -ENOMEDIUM; } else if (bdrv_check_request(bs, sector_num, nb_sectors)) { @@ -4317,55 +4319,55 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, return 0; } - if (bs->drv->bdrv_co_discard) { - int max_discard = bs->bl.max_discard ? - bs->bl.max_discard : MAX_DISCARD_DEFAULT; - - while (nb_sectors > 0) { - int ret; - int num = nb_sectors; - - /* align request */ - if (bs->bl.discard_alignment && - num >= bs->bl.discard_alignment && - sector_num % bs->bl.discard_alignment) { - if (num > bs->bl.discard_alignment) { - num = bs->bl.discard_alignment; - } - num -= sector_num % bs->bl.discard_alignment; - } - - /* limit request size */ - if (num > max_discard) { - num = max_discard; - } - - ret = bs->drv->bdrv_co_discard(bs, sector_num, num); - if (ret) { - return ret; - } - - sector_num += num; - nb_sectors -= num; - } - return 0; - } else if (bs->drv->bdrv_aio_discard) { - BlockDriverAIOCB *acb; - CoroutineIOCompletion co = { - .coroutine = qemu_coroutine_self(), - }; - - acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors, - bdrv_co_io_em_complete, &co); - if (acb == NULL) { - return -EIO; - } else { - qemu_coroutine_yield(); - return co.ret; - } - } else { + if (!bs->drv->bdrv_co_discard && !bs->drv->bdrv_aio_discard) { return 0; } + + max_discard = bs->bl.max_discard ? bs->bl.max_discard : MAX_DISCARD_DEFAULT; + while (nb_sectors > 0) { + int ret; + int num = nb_sectors; + + /* align request */ + if (bs->bl.discard_alignment && + num >= bs->bl.discard_alignment && + sector_num % bs->bl.discard_alignment) { + if (num > bs->bl.discard_alignment) { + num = bs->bl.discard_alignment; + } + num -= sector_num % bs->bl.discard_alignment; + } + + /* limit request size */ + if (num > max_discard) { + num = max_discard; + } + + if (bs->drv->bdrv_co_discard) { + ret = bs->drv->bdrv_co_discard(bs, sector_num, num); + } else { + BlockDriverAIOCB *acb; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors, + bdrv_co_io_em_complete, &co); + if (acb == NULL) { + return -EIO; + } else { + qemu_coroutine_yield(); + ret = co.ret; + } + } + if (ret) { + return ret; + } + + sector_num += num; + nb_sectors -= num; + } + return 0; } int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) From d20d9b7c6723d0123b7d60dd5557aa0a6599f471 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:44 +0100 Subject: [PATCH 05/48] block: add flags to BlockRequest This lets bdrv_co_do_rw receive flags, so that it can be used for zero writes. Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block.c | 17 +++++++++++------ include/block/block.h | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index 506518be88..e993596725 100644 --- a/block.c +++ b/block.c @@ -79,6 +79,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BdrvRequestFlags flags, BlockDriverCompletionFunc *cb, void *opaque, bool is_write); @@ -3669,7 +3670,7 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, { trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque); - return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, + return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0, cb, opaque, false); } @@ -3679,7 +3680,7 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, { trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque); - return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, + return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0, cb, opaque, true); } @@ -3851,8 +3852,10 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs) /* Run the aio requests. */ mcb->num_requests = num_reqs; for (i = 0; i < num_reqs; i++) { - bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov, - reqs[i].nb_sectors, multiwrite_cb, mcb); + bdrv_co_aio_rw_vector(bs, reqs[i].sector, reqs[i].qiov, + reqs[i].nb_sectors, reqs[i].flags, + multiwrite_cb, mcb, + true); } return 0; @@ -3994,10 +3997,10 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque) if (!acb->is_write) { acb->req.error = bdrv_co_do_readv(bs, acb->req.sector, - acb->req.nb_sectors, acb->req.qiov, 0); + acb->req.nb_sectors, acb->req.qiov, acb->req.flags); } else { acb->req.error = bdrv_co_do_writev(bs, acb->req.sector, - acb->req.nb_sectors, acb->req.qiov, 0); + acb->req.nb_sectors, acb->req.qiov, acb->req.flags); } acb->bh = qemu_bh_new(bdrv_co_em_bh, acb); @@ -4008,6 +4011,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BdrvRequestFlags flags, BlockDriverCompletionFunc *cb, void *opaque, bool is_write) @@ -4019,6 +4023,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, acb->req.sector = sector_num; acb->req.nb_sectors = nb_sectors; acb->req.qiov = qiov; + acb->req.flags = flags; acb->is_write = is_write; acb->done = NULL; diff --git a/include/block/block.h b/include/block/block.h index 5beccbf1cf..49e6719116 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -311,6 +311,7 @@ typedef struct BlockRequest { /* Fields to be filled by multiwrite caller */ int64_t sector; int nb_sectors; + int flags; QEMUIOVector *qiov; BlockDriverCompletionFunc *cb; void *opaque; From 94d6ff21f48c8c98e6e9eef58cc6f6346c9dd851 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:45 +0100 Subject: [PATCH 06/48] block: add flags argument to bdrv_co_write_zeroes tracepoint Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block.c | 2 +- trace-events | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index e993596725..1d9da53362 100644 --- a/block.c +++ b/block.c @@ -2888,7 +2888,7 @@ int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors, BdrvRequestFlags flags) { - trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors); + trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors, flags); if (!(bs->open_flags & BDRV_O_UNMAP)) { flags &= ~BDRV_REQ_MAY_UNMAP; diff --git a/trace-events b/trace-events index 8695e9e5b7..f159ac908c 100644 --- a/trace-events +++ b/trace-events @@ -64,7 +64,7 @@ bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" -bdrv_co_write_zeroes(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" +bdrv_co_write_zeroes(void *bs, int64_t sector_num, int nb_sector, int flags) "bs %p sector_num %"PRId64" nb_sectors %d flags %#x" bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p" bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d" From d5ef94d43da8c57a2d597efbdec3d9a54d97fdf7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:46 +0100 Subject: [PATCH 07/48] block: add bdrv_aio_write_zeroes This will be used by the SCSI layer. Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block.c | 11 +++++++++++ include/block/block.h | 3 +++ trace-events | 1 + 3 files changed, 15 insertions(+) diff --git a/block.c b/block.c index 1d9da53362..c491edfb95 100644 --- a/block.c +++ b/block.c @@ -3684,6 +3684,17 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, cb, opaque, true); } +BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, BdrvRequestFlags flags, + BlockDriverCompletionFunc *cb, void *opaque) +{ + trace_bdrv_aio_write_zeroes(bs, sector_num, nb_sectors, flags, opaque); + + return bdrv_co_aio_rw_vector(bs, sector_num, NULL, nb_sectors, + BDRV_REQ_ZERO_WRITE | flags, + cb, opaque, true); +} + typedef struct MultiwriteCB { int error; diff --git a/include/block/block.h b/include/block/block.h index 49e6719116..36efaeac2d 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -216,6 +216,9 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors, BdrvRequestFlags flags); +BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, BdrvRequestFlags flags, + BlockDriverCompletionFunc *cb, void *opaque); int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags); int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov); int bdrv_pread(BlockDriverState *bs, int64_t offset, diff --git a/trace-events b/trace-events index f159ac908c..d318d6f0f9 100644 --- a/trace-events +++ b/trace-events @@ -60,6 +60,7 @@ bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p" bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" +bdrv_aio_write_zeroes(void *bs, int64_t sector_num, int nb_sectors, int flags, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d flags %#x opaque %p" bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" From 7ce21016b69b512bf4777965a4292318f2bc7544 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:47 +0100 Subject: [PATCH 08/48] block: handle ENOTSUP from discard in generic code Similar to write_zeroes, let the generic code receive a ENOTSUP for discard operations. Since bdrv_discard has advisory semantics, we can just swallow the error. Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block.c | 2 +- block/raw-posix.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index c491edfb95..9818052603 100644 --- a/block.c +++ b/block.c @@ -4376,7 +4376,7 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, ret = co.ret; } } - if (ret) { + if (ret && ret != -ENOTSUP) { return ret; } diff --git a/block/raw-posix.c b/block/raw-posix.c index f836c8e745..cfa3162bc0 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -323,10 +323,10 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, } #endif - s->has_discard = 1; + s->has_discard = true; #ifdef CONFIG_XFS if (platform_test_xfs_fd(s->fd)) { - s->is_xfs = 1; + s->is_xfs = true; } #endif @@ -698,8 +698,8 @@ static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb) int ret = -EOPNOTSUPP; BDRVRawState *s = aiocb->bs->opaque; - if (s->has_discard == 0) { - return 0; + if (!s->has_discard) { + return -ENOTSUP; } if (aiocb->aio_type & QEMU_AIO_BLKDEV) { @@ -734,8 +734,8 @@ static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb) if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP || ret == -ENOTTY) { - s->has_discard = 0; - ret = 0; + s->has_discard = false; + ret = -ENOTSUP; } return ret; } From b8d71c09f31a9cae248d167dddc75c66d5135ff2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:48 +0100 Subject: [PATCH 09/48] block: make bdrv_co_do_write_zeroes stricter in producing aligned requests Right now, bdrv_co_do_write_zeroes will only try to align the beginning of the request. However, it is simpler for many formats to expect the block layer to separate both the head *and* the tail. This makes sure that the format's bdrv_co_write_zeroes function will be called with aligned sector_num and nb_sectors for the bulk of the request. Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/block.c b/block.c index 9818052603..831c1508d2 100644 --- a/block.c +++ b/block.c @@ -2771,14 +2771,21 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs, while (nb_sectors > 0 && !ret) { int num = nb_sectors; - /* align request */ - if (bs->bl.write_zeroes_alignment && - num >= bs->bl.write_zeroes_alignment && - sector_num % bs->bl.write_zeroes_alignment) { - if (num > bs->bl.write_zeroes_alignment) { + /* Align request. Block drivers can expect the "bulk" of the request + * to be aligned. + */ + if (bs->bl.write_zeroes_alignment + && num > bs->bl.write_zeroes_alignment) { + if (sector_num % bs->bl.write_zeroes_alignment != 0) { + /* Make a small request up to the first aligned sector. */ num = bs->bl.write_zeroes_alignment; + num -= sector_num % bs->bl.write_zeroes_alignment; + } else if ((sector_num + num) % bs->bl.write_zeroes_alignment != 0) { + /* Shorten the request to the last aligned sector. num cannot + * underflow because num > bs->bl.write_zeroes_alignment. + */ + num -= (sector_num + num) % bs->bl.write_zeroes_alignment; } - num -= sector_num % bs->bl.write_zeroes_alignment; } /* limit request size */ @@ -2796,16 +2803,20 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs, /* Fall back to bounce buffer if write zeroes is unsupported */ iov.iov_len = num * BDRV_SECTOR_SIZE; if (iov.iov_base == NULL) { - /* allocate bounce buffer only once and ensure that it - * is big enough for this and all future requests. - */ - size_t bufsize = num <= nb_sectors ? num : max_write_zeroes; - iov.iov_base = qemu_blockalign(bs, bufsize * BDRV_SECTOR_SIZE); - memset(iov.iov_base, 0, bufsize * BDRV_SECTOR_SIZE); + iov.iov_base = qemu_blockalign(bs, num * BDRV_SECTOR_SIZE); + memset(iov.iov_base, 0, num * BDRV_SECTOR_SIZE); } qemu_iovec_init_external(&qiov, &iov, 1); ret = drv->bdrv_co_writev(bs, sector_num, num, &qiov); + + /* Keep bounce buffer around if it is big enough for all + * all future requests. + */ + if (num < max_write_zeroes) { + qemu_vfree(iov.iov_base); + iov.iov_base = NULL; + } } sector_num += num; From 97b00e285119e611f500686f32f9bccffbb9126a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:49 +0100 Subject: [PATCH 10/48] vpc, vhdx: add get_info Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block/vhdx.c | 10 ++++++++++ block/vpc.c | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/block/vhdx.c b/block/vhdx.c index 7d1af9663b..ed6fa53b87 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1043,6 +1043,15 @@ static void vhdx_block_translate(BDRVVHDXState *s, int64_t sector_num, } +static int vhdx_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +{ + BDRVVHDXState *s = bs->opaque; + + bdi->cluster_size = s->block_size; + + return 0; +} + static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) @@ -1885,6 +1894,7 @@ static BlockDriver bdrv_vhdx = { .bdrv_co_readv = vhdx_co_readv, .bdrv_co_writev = vhdx_co_writev, .bdrv_create = vhdx_create, + .bdrv_get_info = vhdx_get_info, .create_options = vhdx_create_options, }; diff --git a/block/vpc.c b/block/vpc.c index 577cc45992..551876fef7 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -455,6 +455,18 @@ fail: return -1; } +static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +{ + BDRVVPCState *s = (BDRVVPCState *)bs->opaque; + VHDFooter *footer = (VHDFooter *) s->footer_buf; + + if (cpu_to_be32(footer->type) != VHD_FIXED) { + bdi->cluster_size = s->block_size; + } + + return 0; +} + static int vpc_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { @@ -857,6 +869,8 @@ static BlockDriver bdrv_vpc = { .bdrv_read = vpc_co_read, .bdrv_write = vpc_co_write, + .bdrv_get_info = vpc_get_info, + .create_options = vpc_create_options, .bdrv_has_zero_init = vpc_has_zero_init, }; From 95de6d7078b029b73708059a17cef20f332adcb7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:50 +0100 Subject: [PATCH 11/48] block drivers: add discard/write_zeroes properties to bdrv_get_info implementation Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block/qcow2.c | 2 ++ block/qed.c | 2 ++ block/vdi.c | 1 + block/vhdx.c | 3 +++ block/vpc.c | 1 + 5 files changed, 9 insertions(+) diff --git a/block/qcow2.c b/block/qcow2.c index 8e2b6c7548..41e454a2f1 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1893,6 +1893,8 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs) static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQcowState *s = bs->opaque; + bdi->unallocated_blocks_are_zero = true; + bdi->can_write_zeroes_with_unmap = (s->qcow_version >= 3); bdi->cluster_size = s->cluster_size; bdi->vm_state_offset = qcow2_vm_state_offset(s); return 0; diff --git a/block/qed.c b/block/qed.c index adc2736dd7..59516a5704 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1475,6 +1475,8 @@ static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) memset(bdi, 0, sizeof(*bdi)); bdi->cluster_size = s->header.cluster_size; bdi->is_dirty = s->header.features & QED_F_NEED_CHECK; + bdi->unallocated_blocks_are_zero = true; + bdi->can_write_zeroes_with_unmap = true; return 0; } diff --git a/block/vdi.c b/block/vdi.c index b6ec0020dc..2d7490f173 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -331,6 +331,7 @@ static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) logout("\n"); bdi->cluster_size = s->block_size; bdi->vm_state_offset = 0; + bdi->unallocated_blocks_are_zero = true; return 0; } diff --git a/block/vhdx.c b/block/vhdx.c index ed6fa53b87..67bbe103a1 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1049,6 +1049,9 @@ static int vhdx_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) bdi->cluster_size = s->block_size; + bdi->unallocated_blocks_are_zero = + (s->params.data_bits & VHDX_PARAMS_HAS_PARENT) == 0; + return 0; } diff --git a/block/vpc.c b/block/vpc.c index 551876fef7..1d326cbf44 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -464,6 +464,7 @@ static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) bdi->cluster_size = s->block_size; } + bdi->unallocated_blocks_are_zero = true; return 0; } From cffb1ec600de83f693a23578fc2f344c1af9b96f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:51 +0100 Subject: [PATCH 12/48] block drivers: expose requirement for write same alignment from formats This will let misaligned but large requests use zero clusters. This is important because the cluster size is not guest visible. Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block/qcow2.c | 1 + block/qed.c | 1 + block/vmdk.c | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/block/qcow2.c b/block/qcow2.c index 41e454a2f1..19e037406c 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -718,6 +718,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, } qemu_opts_del(opts); + bs->bl.write_zeroes_alignment = s->cluster_sectors; if (s->use_lazy_refcounts && s->qcow_version < 3) { error_setg(errp, "Lazy refcounts require a qcow2 image with at least " diff --git a/block/qed.c b/block/qed.c index 59516a5704..450a1fa2e9 100644 --- a/block/qed.c +++ b/block/qed.c @@ -495,6 +495,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, } } + bs->bl.write_zeroes_alignment = s->header.cluster_size >> BDRV_SECTOR_BITS; s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, qed_need_check_timer_cb, s); diff --git a/block/vmdk.c b/block/vmdk.c index eb84f46a7b..0734bc200c 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -428,6 +428,10 @@ static int vmdk_add_extent(BlockDriverState *bs, extent->l2_size = l2_size; extent->cluster_sectors = flat ? sectors : cluster_sectors; + if (!flat) { + bs->bl.write_zeroes_alignment = + MAX(bs->bl.write_zeroes_alignment, cluster_sectors); + } if (s->num_extents > 1) { extent->end_sector = (*(extent - 1)).end_sector + extent->sectors; } else { From 4b52498e62d02a30f780875f54431d1bad0bcabd Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Fri, 22 Nov 2013 13:39:52 +0100 Subject: [PATCH 13/48] block/iscsi: remove .bdrv_has_zero_init since commit 3ac21627 the default value changed to 0. Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/iscsi.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index b7b52381d6..b6b62aa176 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1505,11 +1505,6 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset) return 0; } -static int iscsi_has_zero_init(BlockDriverState *bs) -{ - return 0; -} - static int iscsi_create(const char *filename, QEMUOptionParameter *options, Error **errp) { @@ -1608,8 +1603,6 @@ static BlockDriver bdrv_iscsi = { .bdrv_aio_writev = iscsi_aio_writev, .bdrv_aio_flush = iscsi_aio_flush, - .bdrv_has_zero_init = iscsi_has_zero_init, - #ifdef __linux__ .bdrv_ioctl = iscsi_ioctl, .bdrv_aio_ioctl = iscsi_aio_ioctl, From 2af8a1a704a352bab2e9eaf803db0b3552e826d0 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Fri, 22 Nov 2013 13:39:53 +0100 Subject: [PATCH 14/48] block/iscsi: updated copyright added myself to reflect recent work on the iscsi block driver. Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/iscsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/iscsi.c b/block/iscsi.c index b6b62aa176..20f4f55e20 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2,6 +2,7 @@ * QEMU Block driver for iSCSI images * * Copyright (c) 2010-2011 Ronnie Sahlberg + * Copyright (c) 2012-2013 Peter Lieven * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal From fa6252b0565526ec2347e248172f91771e0d9f47 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:54 +0100 Subject: [PATCH 15/48] block/iscsi: check WRITE SAME support differently depending on MAY_UNMAP The current check is right for MAY_UNMAP=1. For MAY_UNMAP=0, just try and fall back to regular writes as soon as a WRITE SAME command fails. Signed-off-by: Paolo Bonzini Reviewed-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block/iscsi.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 20f4f55e20..93fee6d1df 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -55,6 +55,7 @@ typedef struct IscsiLun { QEMUTimer *nop_timer; uint8_t lbpme; uint8_t lbprz; + uint8_t has_write_same; struct scsi_inquiry_logical_block_provisioning lbp; struct scsi_inquiry_block_limits bl; unsigned char *zeroblock; @@ -976,8 +977,13 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, return -EINVAL; } - if (!iscsilun->lbp.lbpws) { - /* WRITE SAME is not supported by the target */ + if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) { + /* WRITE SAME without UNMAP is not supported by the target */ + return -ENOTSUP; + } + + if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) { + /* WRITE SAME with UNMAP is not supported by the target */ return -ENOTSUP; } @@ -1012,6 +1018,14 @@ retry: } if (iTask.status != SCSI_STATUS_GOOD) { + if (iTask.status == SCSI_STATUS_CHECK_CONDITION && + iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && + iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) { + /* WRITE SAME is not supported by the target */ + iscsilun->has_write_same = false; + return -ENOTSUP; + } + return -EIO; } @@ -1375,6 +1389,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, } iscsilun->type = inq->periperal_device_type; + iscsilun->has_write_same = true; if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) { goto out; From 260a82e524b7f86c12b8e39d4c3f208af95645f7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:55 +0100 Subject: [PATCH 16/48] raw-posix: implement write_zeroes with MAY_UNMAP for files Writing zeroes to a file can be done by punching a hole if MAY_UNMAP is set. Note that in this case ENOTSUP is not ignored, but makes the block layer fall back to the generic implementation. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/raw-posix.c | 66 +++++++++++++++++++++++++++++++++++++++++++++-- trace-events | 1 + 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index cfa3162bc0..7f3f47d699 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -139,9 +139,10 @@ typedef struct BDRVRawState { void *aio_ctx; #endif #ifdef CONFIG_XFS - bool is_xfs : 1; + bool is_xfs:1; #endif - bool has_discard : 1; + bool has_discard:1; + bool discard_zeroes:1; } BDRVRawState; typedef struct BDRVRawReopenState { @@ -283,6 +284,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, Error *local_err = NULL; const char *filename; int fd, ret; + struct stat st; opts = qemu_opts_create_nofail(&raw_runtime_opts); qemu_opts_absorb_qdict(opts, options, &local_err); @@ -324,6 +326,15 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, #endif s->has_discard = true; + + if (fstat(s->fd, &st) < 0) { + error_setg_errno(errp, errno, "Could not stat file"); + goto fail; + } + if (S_ISREG(st.st_mode)) { + s->discard_zeroes = true; + } + #ifdef CONFIG_XFS if (platform_test_xfs_fd(s->fd)) { s->is_xfs = true; @@ -787,6 +798,29 @@ static int aio_worker(void *arg) return ret; } +static int paio_submit_co(BlockDriverState *bs, int fd, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + int type) +{ + RawPosixAIOData *acb = g_slice_new(RawPosixAIOData); + ThreadPool *pool; + + acb->bs = bs; + acb->aio_type = type; + acb->aio_fildes = fd; + + if (qiov) { + acb->aio_iov = qiov->iov; + acb->aio_niov = qiov->niov; + } + acb->aio_nbytes = nb_sectors * 512; + acb->aio_offset = sector_num * 512; + + trace_paio_submit_co(sector_num, nb_sectors, type); + pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); + return thread_pool_submit_co(pool, aio_worker, acb); +} + static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque, int type) @@ -1199,6 +1233,31 @@ static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs, cb, opaque, QEMU_AIO_DISCARD); } +static int coroutine_fn raw_co_write_zeroes( + BlockDriverState *bs, int64_t sector_num, + int nb_sectors, BdrvRequestFlags flags) +{ + BDRVRawState *s = bs->opaque; + + if (!(flags & BDRV_REQ_MAY_UNMAP)) { + return -ENOTSUP; + } + if (!s->discard_zeroes) { + return -ENOTSUP; + } + return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors, + QEMU_AIO_DISCARD); +} + +static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +{ + BDRVRawState *s = bs->opaque; + + bdi->unallocated_blocks_are_zero = s->discard_zeroes; + bdi->can_write_zeroes_with_unmap = s->discard_zeroes; + return 0; +} + static QEMUOptionParameter raw_create_options[] = { { .name = BLOCK_OPT_SIZE, @@ -1222,6 +1281,7 @@ static BlockDriver bdrv_file = { .bdrv_create = raw_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_get_block_status = raw_co_get_block_status, + .bdrv_co_write_zeroes = raw_co_write_zeroes, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, @@ -1230,6 +1290,7 @@ static BlockDriver bdrv_file = { .bdrv_truncate = raw_truncate, .bdrv_getlength = raw_getlength, + .bdrv_get_info = raw_get_info, .bdrv_get_allocated_file_size = raw_get_allocated_file_size, @@ -1585,6 +1646,7 @@ static BlockDriver bdrv_host_device = { .bdrv_truncate = raw_truncate, .bdrv_getlength = raw_getlength, + .bdrv_get_info = raw_get_info, .bdrv_get_allocated_file_size = raw_get_allocated_file_size, diff --git a/trace-events b/trace-events index d318d6f0f9..e32d00cefb 100644 --- a/trace-events +++ b/trace-events @@ -128,6 +128,7 @@ thread_pool_cancel(void *req, void *opaque) "req %p opaque %p" # block/raw-win32.c # block/raw-posix.c +paio_submit_co(int64_t sector_num, int nb_sectors, int type) "sector_num %"PRId64" nb_sectors %d type %d" paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d" # ioport.c From d0b4503ed2d8713791c38839341b023f78d1a3d9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:56 +0100 Subject: [PATCH 17/48] raw-posix: implement write_zeroes with MAY_UNMAP for block devices See the next commit for the description of the Linux kernel problem that is worked around in raw_open_common. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/raw-posix.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/block/raw-posix.c b/block/raw-posix.c index 7f3f47d699..b3feed611b 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -334,6 +334,22 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, if (S_ISREG(st.st_mode)) { s->discard_zeroes = true; } + if (S_ISBLK(st.st_mode)) { +#ifdef BLKDISCARDZEROES + unsigned int arg; + if (ioctl(s->fd, BLKDISCARDZEROES, &arg) == 0 && arg) { + s->discard_zeroes = true; + } +#endif +#ifdef __linux__ + /* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. Do + * not rely on the contents of discarded blocks unless using O_DIRECT. + */ + if (!(bs->open_flags & BDRV_O_NOCACHE)) { + s->discard_zeroes = false; + } +#endif + } #ifdef CONFIG_XFS if (platform_test_xfs_fd(s->fd)) { @@ -1586,6 +1602,26 @@ static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs, cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV); } +static coroutine_fn int hdev_co_write_zeroes(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, BdrvRequestFlags flags) +{ + BDRVRawState *s = bs->opaque; + int rc; + + rc = fd_open(bs); + if (rc < 0) { + return rc; + } + if (!(flags & BDRV_REQ_MAY_UNMAP)) { + return -ENOTSUP; + } + if (!s->discard_zeroes) { + return -ENOTSUP; + } + return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors, + QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV); +} + static int hdev_create(const char *filename, QEMUOptionParameter *options, Error **errp) { @@ -1638,6 +1674,7 @@ static BlockDriver bdrv_host_device = { .bdrv_reopen_abort = raw_reopen_abort, .bdrv_create = hdev_create, .create_options = raw_create_options, + .bdrv_co_write_zeroes = hdev_co_write_zeroes, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, From 97a2ae34537882df34810d538ab1f51085499d2c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:57 +0100 Subject: [PATCH 18/48] raw-posix: add support for write_zeroes on XFS and block devices The code is similar to the implementation of discard and write_zeroes with UNMAP. However, failure must be propagated up to block.c. The stale page cache problem can be reproduced as follows: # modprobe scsi-debug lbpws=1 lbprz=1 # ./qemu-io /dev/sdXX qemu-io> write -P 0xcc 0 2M qemu-io> write -z 0 1M qemu-io> read -P 0x00 0 512 Pattern verification failed at offset 0, 512 bytes qemu-io> read -v 0 512 00000000: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................ ... # ./qemu-io --cache=none /dev/sdXX qemu-io> write -P 0xcc 0 2M qemu-io> write -z 0 1M qemu-io> read -P 0x00 0 512 qemu-io> read -v 0 512 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ... And similarly with discard instead of "write -z". Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/raw-aio.h | 3 +- block/raw-posix.c | 84 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/block/raw-aio.h b/block/raw-aio.h index c61f1595d9..7ad0a8a0a7 100644 --- a/block/raw-aio.h +++ b/block/raw-aio.h @@ -21,9 +21,10 @@ #define QEMU_AIO_IOCTL 0x0004 #define QEMU_AIO_FLUSH 0x0008 #define QEMU_AIO_DISCARD 0x0010 +#define QEMU_AIO_WRITE_ZEROES 0x0020 #define QEMU_AIO_TYPE_MASK \ (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \ - QEMU_AIO_DISCARD) + QEMU_AIO_DISCARD|QEMU_AIO_WRITE_ZEROES) /* AIO flags */ #define QEMU_AIO_MISALIGNED 0x1000 diff --git a/block/raw-posix.c b/block/raw-posix.c index b3feed611b..10c6b34ba9 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -142,6 +142,7 @@ typedef struct BDRVRawState { bool is_xfs:1; #endif bool has_discard:1; + bool has_write_zeroes:1; bool discard_zeroes:1; } BDRVRawState; @@ -326,6 +327,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, #endif s->has_discard = true; + s->has_write_zeroes = true; if (fstat(s->fd, &st) < 0) { error_setg_errno(errp, errno, "Could not stat file"); @@ -344,9 +346,11 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, #ifdef __linux__ /* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. Do * not rely on the contents of discarded blocks unless using O_DIRECT. + * Same for BLKZEROOUT. */ if (!(bs->open_flags & BDRV_O_NOCACHE)) { s->discard_zeroes = false; + s->has_write_zeroes = false; } #endif } @@ -702,6 +706,23 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb) } #ifdef CONFIG_XFS +static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes) +{ + struct xfs_flock64 fl; + + memset(&fl, 0, sizeof(fl)); + fl.l_whence = SEEK_SET; + fl.l_start = offset; + fl.l_len = bytes; + + if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) { + DEBUG_BLOCK_PRINT("cannot write zero range (%s)\n", strerror(errno)); + return -errno; + } + + return 0; +} + static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes) { struct xfs_flock64 fl; @@ -720,6 +741,42 @@ static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes) } #endif +static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb) +{ + int ret = -EOPNOTSUPP; + BDRVRawState *s = aiocb->bs->opaque; + + if (s->has_write_zeroes == 0) { + return -ENOTSUP; + } + + if (aiocb->aio_type & QEMU_AIO_BLKDEV) { +#ifdef BLKZEROOUT + do { + uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes }; + if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) { + return 0; + } + } while (errno == EINTR); + + ret = -errno; +#endif + } else { +#ifdef CONFIG_XFS + if (s->is_xfs) { + return xfs_write_zeroes(s, aiocb->aio_offset, aiocb->aio_nbytes); + } +#endif + } + + if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP || + ret == -ENOTTY) { + s->has_write_zeroes = false; + ret = -ENOTSUP; + } + return ret; +} + static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb) { int ret = -EOPNOTSUPP; @@ -804,6 +861,9 @@ static int aio_worker(void *arg) case QEMU_AIO_DISCARD: ret = handle_aiocb_discard(aiocb); break; + case QEMU_AIO_WRITE_ZEROES: + ret = handle_aiocb_write_zeroes(aiocb); + break; default: fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); ret = -EINVAL; @@ -1256,13 +1316,13 @@ static int coroutine_fn raw_co_write_zeroes( BDRVRawState *s = bs->opaque; if (!(flags & BDRV_REQ_MAY_UNMAP)) { - return -ENOTSUP; + return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors, + QEMU_AIO_WRITE_ZEROES); + } else if (s->discard_zeroes) { + return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors, + QEMU_AIO_DISCARD); } - if (!s->discard_zeroes) { - return -ENOTSUP; - } - return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors, - QEMU_AIO_DISCARD); + return -ENOTSUP; } static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) @@ -1613,13 +1673,13 @@ static coroutine_fn int hdev_co_write_zeroes(BlockDriverState *bs, return rc; } if (!(flags & BDRV_REQ_MAY_UNMAP)) { - return -ENOTSUP; + return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors, + QEMU_AIO_WRITE_ZEROES|QEMU_AIO_BLKDEV); + } else if (s->discard_zeroes) { + return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors, + QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV); } - if (!s->discard_zeroes) { - return -ENOTSUP; - } - return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors, - QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV); + return -ENOTSUP; } static int hdev_create(const char *filename, QEMUOptionParameter *options, From e18d90c15bab0d47d8f30696058abfb78396081f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:58 +0100 Subject: [PATCH 19/48] qemu-iotests: 033 is fast Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/group | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index b63b18c7aa..303e0f3c2a 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -39,7 +39,7 @@ 030 rw auto backing 031 rw auto quick 032 rw auto -033 rw auto +033 rw auto quick 034 rw auto backing 035 rw auto quick 036 rw auto quick From c5fd1fb038405ed13496761970b3b531f747a892 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:39:59 +0100 Subject: [PATCH 20/48] scsi-disk: catch write protection errors in UNMAP This is the same that is already done for WRITE SAME. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- hw/scsi/scsi-disk.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 74e6a14c29..4138268ad9 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1543,6 +1543,7 @@ done: static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint8_t *p = inbuf; int len = r->req.cmd.xfer; UnmapCBData *data; @@ -1560,6 +1561,11 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) goto invalid_param_len; } + if (bdrv_is_read_only(s->qdev.conf.bs)) { + scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); + return; + } + data = g_new0(UnmapCBData, 1); data->r = r; data->inbuf = &p[8]; From 823bd7391c96ba675f20fd6d952d1cb6e1ffb851 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:40:00 +0100 Subject: [PATCH 21/48] scsi-disk: reject ANCHOR=1 for UNMAP and WRITE SAME commands Since we report ANC_SUP==0 in VPD page B2h, we need to return an error (ILLEGAL REQUEST/INVALID FIELD IN CDB) for all WRITE SAME requests with ANCHOR==1. Inspired by a similar patch to the LIO in-kernel target. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- hw/scsi/scsi-disk.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 4138268ad9..0640bb031d 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1548,6 +1548,11 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) int len = r->req.cmd.xfer; UnmapCBData *data; + /* Reject ANCHOR=1. */ + if (r->req.cmd.buf[1] & 0x1) { + goto invalid_field; + } + if (len < 8) { goto invalid_param_len; } @@ -1578,6 +1583,10 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) invalid_param_len: scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); + return; + +invalid_field: + scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); } static void scsi_disk_emulate_write_data(SCSIRequest *req) @@ -1856,8 +1865,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) /* * We only support WRITE SAME with the unmap bit set for now. + * Reject UNMAP=0 or ANCHOR=1. */ - if (!(req->cmd.buf[1] & 0x8)) { + if (!(req->cmd.buf[1] & 0x8) || (req->cmd.buf[1] & 0x10)) { goto illegal_request; } From 84f94a9a82487639bc87d5f09f938c9f6a61f79a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Nov 2013 13:40:01 +0100 Subject: [PATCH 22/48] scsi-disk: correctly implement WRITE SAME Fetch the data to be written from the input buffer. If it is all zeroes, we can use the write_zeroes call (possibly with the new MAY_UNMAP flag). Otherwise, do as many write cycles as needed, writing 512k at a time. Strictly speaking, this is still incorrect because a zero cluster should only be written if the MAY_UNMAP flag is set. But this is a bug in qcow2 and the other formats, not in the SCSI code. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- hw/scsi/scsi-disk.c | 140 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 116 insertions(+), 24 deletions(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 0640bb031d..efadfc023f 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -41,6 +41,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include #endif +#define SCSI_WRITE_SAME_MAX 524288 #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 #define SCSI_MAX_MODE_LEN 256 @@ -634,6 +635,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) buflen = 0x40; memset(outbuf + 4, 0, buflen - 4); + outbuf[4] = 0x1; /* wsnz */ + /* optimal transfer length granularity */ outbuf[6] = (min_io_size >> 8) & 0xff; outbuf[7] = min_io_size & 0xff; @@ -1589,6 +1592,111 @@ invalid_field: scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); } +typedef struct WriteSameCBData { + SCSIDiskReq *r; + int64_t sector; + int nb_sectors; + QEMUIOVector qiov; + struct iovec iov; +} WriteSameCBData; + +static void scsi_write_same_complete(void *opaque, int ret) +{ + WriteSameCBData *data = opaque; + SCSIDiskReq *r = data->r; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + assert(r->req.aiocb != NULL); + r->req.aiocb = NULL; + bdrv_acct_done(s->qdev.conf.bs, &r->acct); + if (r->req.io_canceled) { + goto done; + } + + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret)) { + goto done; + } + } + + data->nb_sectors -= data->iov.iov_len / 512; + data->sector += data->iov.iov_len / 512; + data->iov.iov_len = MIN(data->nb_sectors * 512, data->iov.iov_len); + if (data->iov.iov_len) { + bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE); + r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector, + &data->qiov, data->iov.iov_len / 512, + scsi_write_same_complete, r); + return; + } + + scsi_req_complete(&r->req, GOOD); + +done: + if (!r->req.io_canceled) { + scsi_req_unref(&r->req); + } + qemu_vfree(data->iov.iov_base); + g_free(data); +} + +static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + uint32_t nb_sectors = scsi_data_cdb_length(r->req.cmd.buf); + WriteSameCBData *data; + uint8_t *buf; + int i; + + /* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1. */ + if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) { + scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); + return; + } + + if (bdrv_is_read_only(s->qdev.conf.bs)) { + scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); + return; + } + if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) { + scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); + return; + } + + if (buffer_is_zero(inbuf, s->qdev.blocksize)) { + int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0; + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + bdrv_acct_start(s->qdev.conf.bs, &r->acct, nb_sectors * s->qdev.blocksize, + BDRV_ACCT_WRITE); + r->req.aiocb = bdrv_aio_write_zeroes(s->qdev.conf.bs, + r->req.cmd.lba * (s->qdev.blocksize / 512), + nb_sectors * (s->qdev.blocksize / 512), + flags, scsi_aio_complete, r); + return; + } + + data = g_new0(WriteSameCBData, 1); + data->r = r; + data->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); + data->nb_sectors = nb_sectors * (s->qdev.blocksize / 512); + data->iov.iov_len = MIN(data->nb_sectors * 512, SCSI_WRITE_SAME_MAX); + data->iov.iov_base = buf = qemu_blockalign(s->qdev.conf.bs, data->iov.iov_len); + qemu_iovec_init_external(&data->qiov, &data->iov, 1); + + for (i = 0; i < data->iov.iov_len; i += s->qdev.blocksize) { + memcpy(&buf[i], inbuf, s->qdev.blocksize); + } + + scsi_req_ref(&r->req); + bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE); + r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector, + &data->qiov, data->iov.iov_len / 512, + scsi_write_same_complete, data); +} + static void scsi_disk_emulate_write_data(SCSIRequest *req) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); @@ -1612,6 +1720,10 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req) scsi_disk_emulate_unmap(r, r->iov.iov_base); break; + case WRITE_SAME_10: + case WRITE_SAME_16: + scsi_disk_emulate_write_same(r, r->iov.iov_base); + break; default: abort(); } @@ -1854,30 +1966,10 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) break; case WRITE_SAME_10: case WRITE_SAME_16: - nb_sectors = scsi_data_cdb_length(r->req.cmd.buf); - if (bdrv_is_read_only(s->qdev.conf.bs)) { - scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); - return 0; - } - if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) { - goto illegal_lba; - } - - /* - * We only support WRITE SAME with the unmap bit set for now. - * Reject UNMAP=0 or ANCHOR=1. - */ - if (!(req->cmd.buf[1] & 0x8) || (req->cmd.buf[1] & 0x10)) { - goto illegal_request; - } - - /* The request is used as the AIO opaque value, so add a ref. */ - scsi_req_ref(&r->req); - r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs, - r->req.cmd.lba * (s->qdev.blocksize / 512), - nb_sectors * (s->qdev.blocksize / 512), - scsi_aio_complete, r); - return 0; + DPRINTF("WRITE SAME %d (len %lu)\n", + req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, + (long)r->req.cmd.xfer); + break; default: DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); From 66f6b8143ba0fd873a0b4b4b3da41cf604bc5a11 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 3 Dec 2013 14:57:52 +0100 Subject: [PATCH 23/48] block: Close backing file early in bdrv_img_create Leaving the backing file open although it is not needed anymore can cause problems if it is opened through a block driver which allows exclusive access only and if the create function of the block driver used for the top image (the one being created) tries to close and reopen the image file (which will include opening the backing file a second time). In particular, this will happen with a backing file opened through qemu-nbd and using qcow2 as the top image file format (which reopens the image to flush it to disk). In addition, the BlockDriverState in bdrv_img_create() is used for the backing file only; it should therefore be made local to the respective block. Signed-off-by: Max Reitz Reviewed-by: Kevin Wolf Reviewed-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- block.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index 831c1508d2..1c83ef1fab 100644 --- a/block.c +++ b/block.c @@ -4713,7 +4713,6 @@ void bdrv_img_create(const char *filename, const char *fmt, { QEMUOptionParameter *param = NULL, *create_options = NULL; QEMUOptionParameter *backing_fmt, *backing_file, *size; - BlockDriverState *bs = NULL; BlockDriver *drv, *proto_drv; BlockDriver *backing_drv = NULL; Error *local_err = NULL; @@ -4792,6 +4791,7 @@ void bdrv_img_create(const char *filename, const char *fmt, size = get_option_parameter(param, BLOCK_OPT_SIZE); if (size && size->value.n == -1) { if (backing_file && backing_file->value.s) { + BlockDriverState *bs; uint64_t size; char buf[32]; int back_flags; @@ -4810,6 +4810,7 @@ void bdrv_img_create(const char *filename, const char *fmt, error_get_pretty(local_err)); error_free(local_err); local_err = NULL; + bdrv_unref(bs); goto out; } bdrv_get_geometry(bs, &size); @@ -4817,6 +4818,8 @@ void bdrv_img_create(const char *filename, const char *fmt, snprintf(buf, sizeof(buf), "%" PRId64, size); set_option_parameter(param, BLOCK_OPT_SIZE, buf); + + bdrv_unref(bs); } else { error_setg(errp, "Image creation needs a size parameter"); goto out; @@ -4847,9 +4850,6 @@ out: free_option_parameters(create_options); free_option_parameters(param); - if (bs) { - bdrv_unref(bs); - } if (error_is_set(&local_err)) { error_propagate(errp, local_err); } From f8413b3c23b08a547ce18609acc6fae5fd04ed5c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 4 Dec 2013 11:06:36 +0100 Subject: [PATCH 24/48] qcow2: Zero-initialise first cluster for new images Strictly speaking, this is only required for has_zero_init() == false, but it's easy enough to just do a cluster-aligned write that is padded with zeros after the header. This fixes that after 'qemu-img create' header extensions are attempted to be parsed that are really just random leftover data. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Reviewed-by: Fam Zheng Reviewed-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/qcow2.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 19e037406c..f29aa88671 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1472,7 +1472,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, * size for any qcow2 image. */ BlockDriverState* bs; - QCowHeader header; + QCowHeader *header; uint8_t* refcount_table; Error *local_err = NULL; int ret; @@ -1490,30 +1490,34 @@ static int qcow2_create2(const char *filename, int64_t total_size, } /* Write the header */ - memset(&header, 0, sizeof(header)); - header.magic = cpu_to_be32(QCOW_MAGIC); - header.version = cpu_to_be32(version); - header.cluster_bits = cpu_to_be32(cluster_bits); - header.size = cpu_to_be64(0); - header.l1_table_offset = cpu_to_be64(0); - header.l1_size = cpu_to_be32(0); - header.refcount_table_offset = cpu_to_be64(cluster_size); - header.refcount_table_clusters = cpu_to_be32(1); - header.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT); - header.header_length = cpu_to_be32(sizeof(header)); + QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header)); + header = g_malloc0(cluster_size); + *header = (QCowHeader) { + .magic = cpu_to_be32(QCOW_MAGIC), + .version = cpu_to_be32(version), + .cluster_bits = cpu_to_be32(cluster_bits), + .size = cpu_to_be64(0), + .l1_table_offset = cpu_to_be64(0), + .l1_size = cpu_to_be32(0), + .refcount_table_offset = cpu_to_be64(cluster_size), + .refcount_table_clusters = cpu_to_be32(1), + .refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT), + .header_length = cpu_to_be32(sizeof(*header)), + }; if (flags & BLOCK_FLAG_ENCRYPT) { - header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); + header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES); } else { - header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); + header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); } if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) { - header.compatible_features |= + header->compatible_features |= cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS); } - ret = bdrv_pwrite(bs, 0, &header, sizeof(header)); + ret = bdrv_pwrite(bs, 0, header, cluster_size); + g_free(header); if (ret < 0) { error_setg_errno(errp, -ret, "Could not write qcow2 header"); goto out; From 3baa84491a43c6ba4909cbff69a9f045df9f4879 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 4 Dec 2013 09:06:58 +0800 Subject: [PATCH 25/48] qemu-iotests: Add "-c " option The option sets cache mode used in the tests. "-nocache" is changed to an alias to "-c none", and internally passes "-t none" to qemu-io. Python scripts will make use of option this in the next commit. Signed-off-by: Fam Zheng Reviewed-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/check | 2 +- tests/qemu-iotests/common | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index f5f328f5f5..dc0105c9f5 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -242,7 +242,7 @@ do fi reference=$seq.out - if (echo $QEMU_IO_OPTIONS | grep -s -- '--nocache' > /dev/null); then + if [ "$CACHEMODE" = "none" ]; then [ -f $seq.out.nocache ] && reference=$seq.out.nocache fi diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common index 8cde7f11fa..4743c9e007 100644 --- a/tests/qemu-iotests/common +++ b/tests/qemu-iotests/common @@ -42,13 +42,16 @@ expunge=true have_test_arg=false randomize=false valgrind=false +cachemode=false rm -f $tmp.list $tmp.tmp $tmp.sed export IMGFMT=raw export IMGFMT_GENERIC=true export IMGPROTO=file export IMGOPTS="" +export CACHEMODE="writethrough" export QEMU_IO_OPTIONS="" +export CACHEMODE_IS_DEFAULT=true for r do @@ -113,7 +116,12 @@ s/ .*//p IMGOPTS="$r" imgopts=false continue - + elif $cachemode + then + CACHEMODE="$r" + CACHEMODE_IS_DEFAULT=false + cachemode=false + continue fi xpand=true @@ -147,6 +155,7 @@ check options -o options -o options to pass to qemu-img create/convert -T output timestamps -r randomize test order + -c mode cache mode testlist options -g group[,group...] include tests from these groups @@ -219,7 +228,8 @@ testlist options xpand=false ;; -nocache) - QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --nocache" + CACHEMODE="none" + CACHEMODE_IS_DEFAULT=false xpand=false ;; @@ -258,6 +268,10 @@ testlist options imgopts=true xpand=false ;; + -c) + cachemode=true + xpand=false + ;; -r) # randomize test order randomize=true xpand=false @@ -334,6 +348,9 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \ done +# Set qemu-io cache mode with $CACHEMODE we have +QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE" + # Set default options for qemu-img create -o if they were not specified _set_default_imgopts From 58cc2ae1e3f9f8cd6830a0af116c51c3355710d3 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 4 Dec 2013 09:06:59 +0800 Subject: [PATCH 26/48] qemu-iotests: Honour cache mode in iotests.py This will allow overriding cache mode from the "-c mode" option. Signed-off-by: Fam Zheng Reviewed-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/iotests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 10c9a99e3a..e4fa9af714 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -37,6 +37,7 @@ qemu_args = os.environ.get('QEMU', 'qemu').strip().split(' ') imgfmt = os.environ.get('IMGFMT', 'raw') imgproto = os.environ.get('IMGPROTO', 'file') test_dir = os.environ.get('TEST_DIR', '/var/tmp') +cachemode = os.environ.get('CACHEMODE') socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper') @@ -96,7 +97,7 @@ class VM(object): '''Add a virtio-blk drive to the VM''' options = ['if=virtio', 'format=%s' % imgfmt, - 'cache=none', + 'cache=%s' % cachemode, 'file=%s' % path, 'id=drive%d' % self._num_drives] if opts: From f210a83c1f809516acd9179d02d8c986c5db24cd Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 4 Dec 2013 09:07:00 +0800 Subject: [PATCH 27/48] qemu-iotests: Add _default_cache_mode and _supported_cache_modes This replaces _unsupported_qemu_io_options and check for support of current cache mode, and allow to provide a default if user didn't specify. Signed-off-by: Fam Zheng Reviewed-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/026 | 3 ++- tests/qemu-iotests/039 | 3 ++- tests/qemu-iotests/052 | 4 ++-- tests/qemu-iotests/common.rc | 25 +++++++++++++++---------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 index ebe29d0168..c9c5f83936 100755 --- a/tests/qemu-iotests/026 +++ b/tests/qemu-iotests/026 @@ -44,7 +44,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _supported_os Linux - +_default_cache_mode "writethrough" +_supported_cache_modes "writethrough" "none" echo "Errors while writing 128 kB" echo diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index 8bade92a80..6abf47267f 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -44,7 +44,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _supported_os Linux -_unsupported_qemu_io_options --nocache +_default_cache_mode "writethrough" +_supported_cache_modes "writethrough" size=128M diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052 index f5f9683e68..4d4e411339 100755 --- a/tests/qemu-iotests/052 +++ b/tests/qemu-iotests/052 @@ -41,8 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto generic _supported_os Linux -_unsupported_qemu_io_options --nocache - +_default_cache_mode "writethrough" +_supported_cache_modes "writethrough" size=128M _make_test_img $size diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 7f6245770a..47cef6dbe4 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -387,18 +387,23 @@ _supported_os() _notrun "not suitable for this OS: $HOSTOS" } -_unsupported_qemu_io_options() +_supported_cache_modes() { - for bad_opt - do - for opt in $QEMU_IO_OPTIONS - do - if [ "$bad_opt" = "$opt" ] - then - _notrun "not suitable for qemu-io option: $bad_opt" - fi - done + for mode; do + if [ "$mode" = "$CACHEMODE" ]; then + return + fi done + _notrun "not suitable for cache mode: $CACHEMODE" +} + +_default_cache_mode() +{ + if $CACHEMODE_IS_DEFAULT; then + CACHEMODE="$1" + QEMU_IO="$QEMU_IO --cache $1" + return + fi } # this test requires that a specified command (executable) exists From e14fb91312b27754aa30e78d4bb4ad5cb183b646 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 4 Dec 2013 09:07:01 +0800 Subject: [PATCH 28/48] qemu-iotests: Change default cache mode to "writeback" So that the tests can run faster. Signed-off-by: Fam Zheng Reviewed-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common index 4743c9e007..b2a0944ae0 100644 --- a/tests/qemu-iotests/common +++ b/tests/qemu-iotests/common @@ -49,7 +49,7 @@ export IMGFMT=raw export IMGFMT_GENERIC=true export IMGPROTO=file export IMGOPTS="" -export CACHEMODE="writethrough" +export CACHEMODE="writeback" export QEMU_IO_OPTIONS="" export CACHEMODE_IS_DEFAULT=true From 236c796432bed70e442aa617807a528c18b1ebd3 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 4 Dec 2013 09:07:02 +0800 Subject: [PATCH 29/48] qemu-iotests: Clean up spaces in usage output Whitespace changes to align columns. Signed-off-by: Fam Zheng Reviewed-by: Benoit Canet Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/common | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common index b2a0944ae0..8b4e22c856 100644 --- a/tests/qemu-iotests/common +++ b/tests/qemu-iotests/common @@ -132,7 +132,7 @@ s/ .*//p echo "Usage: $0 [options] [testlist]"' common options - -v verbose + -v verbose check options -raw test raw (default) @@ -148,20 +148,20 @@ check options -sheepdog test sheepdog -nbd test nbd -ssh test ssh - -xdiff graphical mode diff - -nocache use O_DIRECT on backing file - -misalign misalign memory allocations - -n show me, do not run tests + -xdiff graphical mode diff + -nocache use O_DIRECT on backing file + -misalign misalign memory allocations + -n show me, do not run tests -o options -o options to pass to qemu-img create/convert - -T output timestamps - -r randomize test order + -T output timestamps + -r randomize test order -c mode cache mode testlist options -g group[,group...] include tests from these groups -x group[,group...] exclude tests from these groups NNN include test NNN - NNN-NNN include test range (eg. 012-021) + NNN-NNN include test range (eg. 012-021) ' exit 0 ;; From 34602dd6424c4f1cc414ba672f4f430182b5d9f2 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 4 Dec 2013 09:07:03 +0800 Subject: [PATCH 30/48] qemu-iotests: Split qcow2 only cases in 048 Format "raw" doesn't always work on certain file systems (e.g. tmpfs). Use qcow2 to make the allocation status explicit and split into a new case. [Resolved merge conflict due to "qemu-io> " prompt filter, added 074 to group file, and fixed up s/048/074/ copy-paste mistake. --Stefan] Signed-off-by: Fam Zheng Reviewed-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/048 | 27 ------------ tests/qemu-iotests/048.out | 16 ------- tests/qemu-iotests/074 | 86 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/074.out | 18 ++++++++ tests/qemu-iotests/group | 1 + 5 files changed, 105 insertions(+), 43 deletions(-) create mode 100755 tests/qemu-iotests/074 create mode 100644 tests/qemu-iotests/074.out diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048 index 9def7fcc8c..65da46d6f5 100755 --- a/tests/qemu-iotests/048 +++ b/tests/qemu-iotests/048 @@ -81,32 +81,5 @@ cp "$TEST_IMG" "$TEST_IMG2" io_pattern write 512 512 0 1 101 _compare -# Test cluster allocated in one, with IO error -cat > "$TEST_DIR/blkdebug.conf"<&1 |\ - _filter_testdir | _filter_imgfmt - -# Test cluster allocated in one, with different sizes and IO error in the part -# that exists only in one image -cat > "$TEST_DIR/blkdebug.conf"<&1 |\ - _filter_testdir | _filter_imgfmt - # Cleanup status=0 diff --git a/tests/qemu-iotests/048.out b/tests/qemu-iotests/048.out index 58d03d3d79..c0f380d3a3 100644 --- a/tests/qemu-iotests/048.out +++ b/tests/qemu-iotests/048.out @@ -37,20 +37,4 @@ wrote 512/512 bytes at offset 512 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Content mismatch at offset 512! 1 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -=== IO: pattern 102 -wrote 512/512 bytes at offset 512 -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error -qemu-img: Error while reading offset 0: Input/output error -4 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=0 -=== IO: pattern 102 -wrote 512/512 bytes at offset 512 -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error -qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error -Warning: Image size mismatch! -4 Cleanup diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074 new file mode 100755 index 0000000000..aba126cb69 --- /dev/null +++ b/tests/qemu-iotests/074 @@ -0,0 +1,86 @@ +#!/bin/bash +## +## qemu-img compare test (qcow2 only ones) +## +## +## Copyright (C) 2013 Red Hat, Inc. +## +## 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 . +## +# +# creator +owner=famz@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + echo "Cleanup" + _cleanup_test_img + rm "${TEST_IMG2}" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_compare() +{ + $QEMU_IMG compare "$@" "$TEST_IMG" "${TEST_IMG2}" + echo $? +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +# Setup test basic parameters +TEST_IMG2=$TEST_IMG.2 +CLUSTER_SIZE=4096 +size=1024M + +# Test cluster allocated in one, with IO error +cat > "$TEST_DIR/blkdebug.conf"<&1 |\ + _filter_testdir | _filter_imgfmt + +# Test cluster allocated in one, with different sizes and IO error in the part +# that exists only in one image +cat > "$TEST_DIR/blkdebug.conf"<&1 |\ + _filter_testdir | _filter_imgfmt + +# Cleanup +status=0 diff --git a/tests/qemu-iotests/074.out b/tests/qemu-iotests/074.out new file mode 100644 index 0000000000..8fba5aea9c --- /dev/null +++ b/tests/qemu-iotests/074.out @@ -0,0 +1,18 @@ +QA output created by 074 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +=== IO: pattern 102 +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error +qemu-img: Error while reading offset 0: Input/output error +4 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=0 +=== IO: pattern 102 +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error +qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error +Warning: Image size mismatch! +4 +Cleanup diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 303e0f3c2a..ed10720b2d 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -77,3 +77,4 @@ 069 rw auto 070 rw auto 073 rw auto +074 rw auto From 7b4c4781e390a041fa0ef70817678f1b97fc6db6 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 4 Dec 2013 17:10:54 +0800 Subject: [PATCH 31/48] snapshot: distinguish id and name in load_tmp Since later this function will be used so improve it. The only caller of it now is qemu-img, and it is not impacted by introduce function bdrv_snapshot_load_tmp_by_id_or_name() that call bdrv_snapshot_load_tmp() twice to keep old search logic. bdrv_snapshot_load_tmp_by_id_or_name() return int to let caller know the errno, and errno will be used later. Also fix a typo in comments of bdrv_snapshot_delete(). Signed-off-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- block/qcow2-snapshot.c | 10 +++++-- block/qcow2.h | 5 +++- block/snapshot.c | 59 +++++++++++++++++++++++++++++++++++++-- include/block/block_int.h | 4 ++- include/block/snapshot.h | 7 ++++- qemu-img.c | 8 ++++-- 6 files changed, 83 insertions(+), 10 deletions(-) diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 3529c683c6..ad8bf3dcd9 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -675,7 +675,10 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) return s->nb_snapshots; } -int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name) +int qcow2_snapshot_load_tmp(BlockDriverState *bs, + const char *snapshot_id, + const char *name, + Error **errp) { int i, snapshot_index; BDRVQcowState *s = bs->opaque; @@ -687,8 +690,10 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name) assert(bs->read_only); /* Search the snapshot */ - snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name); + snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name); if (snapshot_index < 0) { + error_setg(errp, + "Can't find snapshot"); return -ENOENT; } sn = &s->snapshots[snapshot_index]; @@ -699,6 +704,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name) ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes); if (ret < 0) { + error_setg(errp, "Failed to read l1 table for snapshot"); g_free(new_l1_table); return ret; } diff --git a/block/qcow2.h b/block/qcow2.h index 922e19062a..303eb26629 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -488,7 +488,10 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *name, Error **errp); int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab); -int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name); +int qcow2_snapshot_load_tmp(BlockDriverState *bs, + const char *snapshot_id, + const char *name, + Error **errp); void qcow2_free_snapshots(BlockDriverState *bs); int qcow2_read_snapshots(BlockDriverState *bs); diff --git a/block/snapshot.c b/block/snapshot.c index a05c0c0be0..565222e24a 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -194,7 +194,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, * If only @snapshot_id is specified, delete the first one with id * @snapshot_id. * If only @name is specified, delete the first one with name @name. - * if none is specified, return -ENINVAL. + * if none is specified, return -EINVAL. * * Returns: 0 on success, -errno on failure. If @bs is not inserted, return * -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs @@ -265,18 +265,71 @@ int bdrv_snapshot_list(BlockDriverState *bs, return -ENOTSUP; } +/** + * Temporarily load an internal snapshot by @snapshot_id and @name. + * @bs: block device used in the operation + * @snapshot_id: unique snapshot ID, or NULL + * @name: snapshot name, or NULL + * @errp: location to store error + * + * If both @snapshot_id and @name are specified, load the first one with + * id @snapshot_id and name @name. + * If only @snapshot_id is specified, load the first one with id + * @snapshot_id. + * If only @name is specified, load the first one with name @name. + * if none is specified, return -EINVAL. + * + * Returns: 0 on success, -errno on fail. If @bs is not inserted, return + * -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support + * internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and + * @name, return -ENOENT. If @errp != NULL, it will always be filled on + * failure. + */ int bdrv_snapshot_load_tmp(BlockDriverState *bs, - const char *snapshot_name) + const char *snapshot_id, + const char *name, + Error **errp) { BlockDriver *drv = bs->drv; + if (!drv) { + error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); return -ENOMEDIUM; } + if (!snapshot_id && !name) { + error_setg(errp, "snapshot_id and name are both NULL"); + return -EINVAL; + } if (!bs->read_only) { + error_setg(errp, "Device is not readonly"); return -EINVAL; } if (drv->bdrv_snapshot_load_tmp) { - return drv->bdrv_snapshot_load_tmp(bs, snapshot_name); + return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp); } + error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + drv->format_name, bdrv_get_device_name(bs), + "temporarily load internal snapshot"); return -ENOTSUP; } + +int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, + const char *id_or_name, + Error **errp) +{ + int ret; + Error *local_err = NULL; + + ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err); + if (ret == -ENOENT || ret == -EINVAL) { + error_free(local_err); + local_err = NULL; + ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err); + } + + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + } + + return ret; +} diff --git a/include/block/block_int.h b/include/block/block_int.h index 773899b500..ec0797ebc7 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -176,7 +176,9 @@ struct BlockDriver { int (*bdrv_snapshot_list)(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, - const char *snapshot_name); + const char *snapshot_id, + const char *name, + Error **errp); int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs); diff --git a/include/block/snapshot.h b/include/block/snapshot.h index 012bf226d3..d05bea7223 100644 --- a/include/block/snapshot.h +++ b/include/block/snapshot.h @@ -61,5 +61,10 @@ void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs, int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); int bdrv_snapshot_load_tmp(BlockDriverState *bs, - const char *snapshot_name); + const char *snapshot_id, + const char *name, + Error **errp); +int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, + const char *id_or_name, + Error **errp); #endif diff --git a/qemu-img.c b/qemu-img.c index dc0c2f0ed3..685c566d22 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1264,8 +1264,12 @@ static int img_convert(int argc, char **argv) ret = -1; goto out; } - if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) { - error_report("Failed to load snapshot"); + + bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err); + if (error_is_set(&local_err)) { + error_report("Failed to load snapshot: %s", + error_get_pretty(local_err)); + error_free(local_err); ret = -1; goto out; } From 8c116b0e4141400f8d43a7e6dac8ff3adcc8aadd Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 4 Dec 2013 17:10:55 +0800 Subject: [PATCH 32/48] qemu-nbd: support internal snapshot export Now it is possible to directly export an internal snapshot, which can be used to probe the snapshot's contents without qemu-img convert. Signed-off-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- block/snapshot.c | 18 ++++++++++++++++ include/block/snapshot.h | 8 +++++++ qemu-nbd.c | 46 ++++++++++++++++++++++++++++++++++++++-- qemu-nbd.texi | 8 ++++++- 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/block/snapshot.c b/block/snapshot.c index 565222e24a..9047f8ddc9 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -25,6 +25,24 @@ #include "block/snapshot.h" #include "block/block_int.h" +QemuOptsList internal_snapshot_opts = { + .name = "snapshot", + .head = QTAILQ_HEAD_INITIALIZER(internal_snapshot_opts.head), + .desc = { + { + .name = SNAPSHOT_OPT_ID, + .type = QEMU_OPT_STRING, + .help = "snapshot id" + },{ + .name = SNAPSHOT_OPT_NAME, + .type = QEMU_OPT_STRING, + .help = "snapshot name" + },{ + /* end of list */ + } + }, +}; + int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, const char *name) { diff --git a/include/block/snapshot.h b/include/block/snapshot.h index d05bea7223..770d9bbc8c 100644 --- a/include/block/snapshot.h +++ b/include/block/snapshot.h @@ -27,6 +27,14 @@ #include "qemu-common.h" #include "qapi/error.h" +#include "qemu/option.h" + + +#define SNAPSHOT_OPT_BASE "snapshot." +#define SNAPSHOT_OPT_ID "snapshot.id" +#define SNAPSHOT_OPT_NAME "snapshot.name" + +extern QemuOptsList internal_snapshot_opts; typedef struct QEMUSnapshotInfo { char id_str[128]; /* unique snapshot id */ diff --git a/qemu-nbd.c b/qemu-nbd.c index c26c98ef1d..fe6053ca56 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -20,6 +20,7 @@ #include "block/block.h" #include "block/nbd.h" #include "qemu/main-loop.h" +#include "block/snapshot.h" #include #include @@ -79,7 +80,14 @@ static void usage(const char *name) "\n" "Block device options:\n" " -r, --read-only export read-only\n" -" -s, --snapshot use snapshot file\n" +" -s, --snapshot use FILE as an external snapshot, create a temporary\n" +" file with backing_file=FILE, redirect the write to\n" +" the temporary one\n" +" -l, --load-snapshot=SNAPSHOT_PARAM\n" +" load an internal snapshot inside FILE and export it\n" +" as an read-only device, SNAPSHOT_PARAM format is\n" +" 'snapshot.id=[ID],snapshot.name=[NAME]', or\n" +" '[ID_OR_NAME]'\n" " -n, --nocache disable host cache\n" " --cache=MODE set cache mode (none, writeback, ...)\n" #ifdef CONFIG_LINUX_AIO @@ -315,7 +323,9 @@ int main(int argc, char **argv) char *device = NULL; int port = NBD_DEFAULT_PORT; off_t fd_size; - const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:t"; + QemuOpts *sn_opts = NULL; + const char *sn_id_or_name = NULL; + const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:"; struct option lopt[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, @@ -328,6 +338,7 @@ int main(int argc, char **argv) { "connect", 1, NULL, 'c' }, { "disconnect", 0, NULL, 'd' }, { "snapshot", 0, NULL, 's' }, + { "load-snapshot", 1, NULL, 'l' }, { "nocache", 0, NULL, 'n' }, { "cache", 1, NULL, QEMU_NBD_OPT_CACHE }, #ifdef CONFIG_LINUX_AIO @@ -428,6 +439,17 @@ int main(int argc, char **argv) errx(EXIT_FAILURE, "Offset must be positive `%s'", optarg); } break; + case 'l': + if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { + sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0); + if (!sn_opts) { + errx(EXIT_FAILURE, "Failed in parsing snapshot param `%s'", + optarg); + } + } else { + sn_id_or_name = optarg; + } + /* fall through */ case 'r': nbdflags |= NBD_FLAG_READ_ONLY; flags &= ~BDRV_O_RDWR; @@ -581,6 +603,22 @@ int main(int argc, char **argv) error_get_pretty(local_err)); } + if (sn_opts) { + ret = bdrv_snapshot_load_tmp(bs, + qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID), + qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME), + &local_err); + } else if (sn_id_or_name) { + ret = bdrv_snapshot_load_tmp_by_id_or_name(bs, sn_id_or_name, + &local_err); + } + if (ret < 0) { + errno = -ret; + err(EXIT_FAILURE, + "Failed to load snapshot: %s", + error_get_pretty(local_err)); + } + fd_size = bdrv_getlength(bs); if (partition != -1) { @@ -641,6 +679,10 @@ int main(int argc, char **argv) unlink(sockpath); } + if (sn_opts) { + qemu_opts_del(sn_opts); + } + if (device) { void *ret; pthread_join(client_thread, &ret); diff --git a/qemu-nbd.texi b/qemu-nbd.texi index 6055ec693b..5b55f769ac 100644 --- a/qemu-nbd.texi +++ b/qemu-nbd.texi @@ -27,7 +27,13 @@ Export QEMU disk image using NBD protocol. @item -P, --partition=@var{num} only expose partition @var{num} @item -s, --snapshot - use snapshot file + use @var{filename} as an external snapshot, create a temporary + file with backing_file=@var{filename}, redirect the write to + the temporary one +@item -l, --load-snapshot=@var{snapshot_param} + load an internal snapshot inside @var{filename} and export it + as an read-only device, @var{snapshot_param} format is + 'snapshot.id=[ID],snapshot.name=[NAME]' or '[ID_OR_NAME]' @item -n, --nocache @itemx --cache=@var{cache} set cache mode to be used with the file. See the documentation of From 9c468a013fd0b0eb6154f8c5cfd2b1d498a86113 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 4 Dec 2013 17:10:56 +0800 Subject: [PATCH 33/48] qemu-iotests: add 058 internal snapshot export with qemu-nbd case This case can't run when IMGPROTO=nbd, since it needs to create some internal snapshot which would fail for EOF write request, even when TEST_IMG is exported with "-f raw" in common.rc, so set _supported_proto to file. _require_command() is changed to tip what util is missing, instead of printing a blank. Signed-off-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/058 | 121 +++++++++++++++++++++++++++++++++++ tests/qemu-iotests/058.out | 32 +++++++++ tests/qemu-iotests/check | 1 + tests/qemu-iotests/common.rc | 3 +- tests/qemu-iotests/group | 1 + 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100755 tests/qemu-iotests/058 create mode 100644 tests/qemu-iotests/058.out diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058 new file mode 100755 index 0000000000..cf50857321 --- /dev/null +++ b/tests/qemu-iotests/058 @@ -0,0 +1,121 @@ +#!/bin/bash +# +# Test export internal snapshot by qemu-nbd. +# +# Copyright (C) 2013 IBM, Inc. +# +# Based on 029. +# +# 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 . +# + +# creator +owner=xiawenc@linux.vnet.ibm.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +nbd_unix_socket=$TEST_DIR/test_qemu_nbd_socket +nbd_snapshot_img="nbd:unix:$nbd_unix_socket" + +_cleanup_nbd() +{ + if [ -n "$NBD_SNAPSHOT_PID" ]; then + kill "$NBD_SNAPSHOT_PID" + fi + rm -f "$nbd_unix_socket" +} + +_wait_for_nbd() +{ + for ((i = 0; i < 300; i++)) + do + if [ -r "$nbd_unix_socket" ]; then + return + fi + sleep 0.1 + done + echo "Failed in check of unix socket created by qemu-nbd" + exit 1 +} + +_export_nbd_snapshot() +{ + _cleanup_nbd + $QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l $1 & + NBD_SNAPSHOT_PID=$! + _wait_for_nbd +} + +_export_nbd_snapshot1() +{ + _cleanup_nbd + $QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l snapshot.name=$1 & + NBD_SNAPSHOT_PID=$! + _wait_for_nbd +} + +_cleanup() +{ + _cleanup_nbd + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt qcow2 +_supported_proto file +_require_command QEMU_NBD + +echo +echo "== preparing image ==" +_make_test_img 64M +$QEMU_IO -c 'write -P 0xa 0x1000 0x1000' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'write -P 0xb 0x2000 0x1000' "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG snapshot -c sn1 "$TEST_IMG" +$QEMU_IO -c 'write -P 0xc 0x1000 0x1000' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'write -P 0xd 0x2000 0x1000' "$TEST_IMG" | _filter_qemu_io +_check_test_img + +echo +echo "== verifying the image file with patterns ==" +$QEMU_IO -c 'read -P 0xc 0x1000 0x1000' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'read -P 0xd 0x2000 0x1000' "$TEST_IMG" | _filter_qemu_io + +_export_nbd_snapshot sn1 + +echo +echo "== verifying the exported snapshot with patterns, method 1 ==" +$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io + +_export_nbd_snapshot1 sn1 + +echo +echo "== verifying the exported snapshot with patterns, method 2 ==" +$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/058.out b/tests/qemu-iotests/058.out new file mode 100644 index 0000000000..768ac61a39 --- /dev/null +++ b/tests/qemu-iotests/058.out @@ -0,0 +1,32 @@ +QA output created by 058 + +== preparing image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 4096/4096 bytes at offset 4096 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 4096/4096 bytes at offset 8192 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 4096/4096 bytes at offset 4096 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 4096/4096 bytes at offset 8192 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. + +== verifying the image file with patterns == +read 4096/4096 bytes at offset 4096 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 8192 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying the exported snapshot with patterns, method 1 == +read 4096/4096 bytes at offset 4096 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 8192 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying the exported snapshot with patterns, method 2 == +read 4096/4096 bytes at offset 4096 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 8192 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index dc0105c9f5..e2ed5a95f8 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -161,6 +161,7 @@ cat < Date: Wed, 4 Dec 2013 17:10:57 +0800 Subject: [PATCH 34/48] qemu-img: add -l for snapshot in convert Now qemu-img convert have similar options as qemu-nbd for internal snapshot. Signed-off-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- qemu-img-cmds.hx | 4 ++-- qemu-img.c | 44 +++++++++++++++++++++++++++++++++++--------- qemu-img.texi | 12 ++++++++---- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index da1d965f3e..d02960921a 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -34,9 +34,9 @@ STEXI ETEXI DEF("convert", img_convert, - "convert [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename") + "convert [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename") STEXI -@item convert [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI DEF("info", img_info, diff --git a/qemu-img.c b/qemu-img.c index 685c566d22..54ae984979 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -93,6 +93,11 @@ static void help(void) " 'options' is a comma separated list of format specific options in a\n" " name=value format. Use -o ? for an overview of the options supported by the\n" " used format\n" + " 'snapshot_param' is param used for internal snapshot, format\n" + " is 'snapshot.id=[ID],snapshot.name=[NAME]', or\n" + " '[ID_OR_NAME]'\n" + " 'snapshot_id_or_name' is deprecated, use 'snapshot_param'\n" + " instead\n" " '-c' indicates that target image must be compressed (qcow format only)\n" " '-u' enables unsafe rebasing. It is assumed that old and new backing file\n" " match exactly. The image doesn't need a working backing file before\n" @@ -1144,6 +1149,7 @@ static int img_convert(int argc, char **argv) int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */ bool quiet = false; Error *local_err = NULL; + QemuOpts *sn_opts = NULL; fmt = NULL; out_fmt = "raw"; @@ -1152,7 +1158,7 @@ static int img_convert(int argc, char **argv) compress = 0; skip_create = 0; for(;;) { - c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:qn"); + c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:qnl:"); if (c == -1) { break; } @@ -1187,6 +1193,18 @@ static int img_convert(int argc, char **argv) case 's': snapshot_name = optarg; break; + case 'l': + if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { + sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0); + if (!sn_opts) { + error_report("Failed in parsing snapshot param '%s'", + optarg); + return 1; + } + } else { + snapshot_name = optarg; + } + break; case 'S': { int64_t sval; @@ -1258,7 +1276,12 @@ static int img_convert(int argc, char **argv) total_sectors += bs_sectors; } - if (snapshot_name != NULL) { + if (sn_opts) { + ret = bdrv_snapshot_load_tmp(bs[0], + qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID), + qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME), + &local_err); + } else if (snapshot_name != NULL) { if (bs_n > 1) { error_report("No support for concatenating multiple snapshot"); ret = -1; @@ -1266,13 +1289,13 @@ static int img_convert(int argc, char **argv) } bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err); - if (error_is_set(&local_err)) { - error_report("Failed to load snapshot: %s", - error_get_pretty(local_err)); - error_free(local_err); - ret = -1; - goto out; - } + } + if (error_is_set(&local_err)) { + error_report("Failed to load snapshot: %s", + error_get_pretty(local_err)); + error_free(local_err); + ret = -1; + goto out; } /* Find driver and parse its options */ @@ -1571,6 +1594,9 @@ out: free_option_parameters(create_options); free_option_parameters(param); qemu_vfree(buf); + if (sn_opts) { + qemu_opts_del(sn_opts); + } if (out_bs) { bdrv_unref(out_bs); } diff --git a/qemu-img.texi b/qemu-img.texi index da36975d70..be31191e43 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -46,7 +46,11 @@ is the destination disk image filename is a comma separated list of format specific options in a name=value format. Use @code{-o ?} for an overview of the options supported by the used format or see the format descriptions below for details. - +@item snapshot_param +is param used for internal snapshot, format is +'snapshot.id=[ID],snapshot.name=[NAME]' or '[ID_OR_NAME]' +@item snapshot_id_or_name +is deprecated, use snapshot_param instead @item -c indicates that target image must be compressed (qcow format only) @@ -179,10 +183,10 @@ Error on reading data @end table -@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} -Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename} -using format @var{output_fmt}. It can be optionally compressed (@code{-c} +Convert the disk image @var{filename} or a snapshot @var{snapshot_param}(@var{snapshot_id_or_name} is deprecated) +to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c} option) or use any format specific options like encryption (@code{-o} option). Only the formats @code{qcow} and @code{qcow2} support compression. The From f33d287393d58f5513d25b097310ed4706fbf5b5 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 4 Dec 2013 17:10:58 +0800 Subject: [PATCH 35/48] qemu-iotests: add test for snapshot in qemu-img convert Signed-off-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/058 | 19 ++++++++++++++++++- tests/qemu-iotests/058.out | 12 ++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058 index cf50857321..14584cdea2 100755 --- a/tests/qemu-iotests/058 +++ b/tests/qemu-iotests/058 @@ -1,6 +1,6 @@ #!/bin/bash # -# Test export internal snapshot by qemu-nbd. +# Test export internal snapshot by qemu-nbd, convert it by qemu-img. # # Copyright (C) 2013 IBM, Inc. # @@ -54,6 +54,8 @@ _wait_for_nbd() exit 1 } +converted_image=$TEST_IMG.converted + _export_nbd_snapshot() { _cleanup_nbd @@ -74,6 +76,7 @@ _cleanup() { _cleanup_nbd _cleanup_test_img + rm -f "$converted_image" } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -115,6 +118,20 @@ echo "== verifying the exported snapshot with patterns, method 2 ==" $QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io $QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$QEMU_IMG convert "$TEST_IMG" -l sn1 -O qcow2 "$converted_image" + +echo +echo "== verifying the converted snapshot with patterns, method 1 ==" +$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$converted_image" | _filter_qemu_io +$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$converted_image" | _filter_qemu_io + +$QEMU_IMG convert "$TEST_IMG" -l snapshot.name=sn1 -O qcow2 "$converted_image" + +echo +echo "== verifying the converted snapshot with patterns, method 2 ==" +$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$converted_image" | _filter_qemu_io +$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$converted_image" | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/058.out b/tests/qemu-iotests/058.out index 768ac61a39..9a69379589 100644 --- a/tests/qemu-iotests/058.out +++ b/tests/qemu-iotests/058.out @@ -29,4 +29,16 @@ read 4096/4096 bytes at offset 4096 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 4096/4096 bytes at offset 8192 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying the converted snapshot with patterns, method 1 == +read 4096/4096 bytes at offset 4096 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 8192 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying the converted snapshot with patterns, method 2 == +read 4096/4096 bytes at offset 4096 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 8192 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done From 4323fdcf9451deaaf48468afa91b8bcaeac00cff Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 4 Dec 2013 17:10:59 +0800 Subject: [PATCH 36/48] qemu-nbd: add doc for option -f Signed-off-by: Wenchao Xia Signed-off-by: Stefan Hajnoczi --- qemu-nbd.c | 1 + qemu-nbd.texi | 2 ++ 2 files changed, 3 insertions(+) diff --git a/qemu-nbd.c b/qemu-nbd.c index fe6053ca56..136e8c9c05 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -79,6 +79,7 @@ static void usage(const char *name) #endif "\n" "Block device options:\n" +" -f, --format=FORMAT set image format (raw, qcow2, ...)\n" " -r, --read-only export read-only\n" " -s, --snapshot use FILE as an external snapshot, create a temporary\n" " file with backing_file=FILE, redirect the write to\n" diff --git a/qemu-nbd.texi b/qemu-nbd.texi index 5b55f769ac..0a7e01385c 100644 --- a/qemu-nbd.texi +++ b/qemu-nbd.texi @@ -22,6 +22,8 @@ Export QEMU disk image using NBD protocol. interface to bind to (default @samp{0.0.0.0}) @item -k, --socket=@var{path} Use a unix socket with path @var{path} +@item -f, --format=@var{format} + Set image format as @var{format} @item -r, --read-only export read-only @item -P, --partition=@var{num} From 13c28af87a5541a9b09a59502b876a1725fb502d Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 27 Nov 2013 11:07:01 +0100 Subject: [PATCH 37/48] qemu-img: add support for skipping zeroes in input during convert we currently do not check if a sector is allocated during convert. This means if a sector is unallocated that we allocate a bounce buffer of zeroes, find out its zero later and do not write it in the best case. In the worst case this can lead to reading blocks from a raw device (like iSCSI) altough we could easily know via get_block_status that they are zero and simply skip them. This patch also fixes the progress output not being at 100% after a successful conversion. Signed-off-by: Peter Lieven Reviewed-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- qemu-img.c | 80 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 54ae984979..9d1b6b500a 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1130,13 +1130,15 @@ out3: static int img_convert(int argc, char **argv) { - int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, + int c, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors, skip_create; + int64_t ret = 0; int progress = 0, flags; const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename; BlockDriver *drv, *proto_drv; BlockDriverState **bs = NULL, *out_bs = NULL; - int64_t total_sectors, nb_sectors, sector_num, bs_offset; + int64_t total_sectors, nb_sectors, sector_num, bs_offset, + sector_num_next_status = 0; uint64_t bs_sectors; uint8_t * buf = NULL; const uint8_t *buf1; @@ -1145,7 +1147,6 @@ static int img_convert(int argc, char **argv) QEMUOptionParameter *out_baseimg_param; char *options = NULL; const char *snapshot_name = NULL; - float local_progress = 0; int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */ bool quiet = false; Error *local_err = NULL; @@ -1430,10 +1431,6 @@ static int img_convert(int argc, char **argv) sector_num = 0; nb_sectors = total_sectors; - if (nb_sectors != 0) { - local_progress = (float)100 / - (nb_sectors / MIN(nb_sectors, cluster_sectors)); - } for(;;) { int64_t bs_num; @@ -1491,7 +1488,7 @@ static int img_convert(int argc, char **argv) } } sector_num += n; - qemu_progress_print(local_progress, 100); + qemu_progress_print(100.0 * sector_num / total_sectors, 0); } /* signal EOF to align */ bdrv_write_compressed(out_bs, 0, NULL, 0); @@ -1508,21 +1505,13 @@ static int img_convert(int argc, char **argv) sector_num = 0; // total number of sectors converted so far nb_sectors = total_sectors - sector_num; - if (nb_sectors != 0) { - local_progress = (float)100 / - (nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512)); - } for(;;) { nb_sectors = total_sectors - sector_num; if (nb_sectors <= 0) { + ret = 0; break; } - if (nb_sectors >= (IO_BUF_SIZE / 512)) { - n = (IO_BUF_SIZE / 512); - } else { - n = nb_sectors; - } while (sector_num - bs_offset >= bs_sectors) { bs_i ++; @@ -1534,34 +1523,46 @@ static int img_convert(int argc, char **argv) sector_num, bs_i, bs_offset, bs_sectors); */ } - if (n > bs_offset + bs_sectors - sector_num) { - n = bs_offset + bs_sectors - sector_num; - } - - /* If the output image is being created as a copy on write image, - assume that sectors which are unallocated in the input image - are present in both the output's and input's base images (no - need to copy them). */ - if (out_baseimg) { - ret = bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, - n, &n1); + if ((out_baseimg || has_zero_init) && + sector_num >= sector_num_next_status) { + n = nb_sectors > INT_MAX ? INT_MAX : nb_sectors; + ret = bdrv_get_block_status(bs[bs_i], sector_num - bs_offset, + n, &n1); if (ret < 0) { - error_report("error while reading metadata for sector " - "%" PRId64 ": %s", - sector_num - bs_offset, strerror(-ret)); + error_report("error while reading block status of sector %" + PRId64 ": %s", sector_num - bs_offset, + strerror(-ret)); goto out; } - if (!ret) { + /* If the output image is zero initialized, we are not working + * on a shared base and the input is zero we can skip the next + * n1 sectors */ + if (has_zero_init && !out_baseimg && (ret & BDRV_BLOCK_ZERO)) { sector_num += n1; continue; } - /* The next 'n1' sectors are allocated in the input image. Copy - only those as they may be followed by unallocated sectors. */ - n = n1; - } else { - n1 = n; + /* If the output image is being created as a copy on write + * image, assume that sectors which are unallocated in the + * input image are present in both the output's and input's + * base images (no need to copy them). */ + if (out_baseimg) { + if (!(ret & BDRV_BLOCK_DATA)) { + sector_num += n1; + continue; + } + /* The next 'n1' sectors are allocated in the input image. + * Copy only those as they may be followed by unallocated + * sectors. */ + nb_sectors = n1; + } + /* avoid redundant callouts to get_block_status */ + sector_num_next_status = sector_num + n1; } + n = MIN(nb_sectors, IO_BUF_SIZE / 512); + n = MIN(n, bs_sectors - (sector_num - bs_offset)); + n1 = n; + ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n); if (ret < 0) { error_report("error while reading sector %" PRId64 ": %s", @@ -1586,10 +1587,13 @@ static int img_convert(int argc, char **argv) n -= n1; buf1 += n1 * 512; } - qemu_progress_print(local_progress, 100); + qemu_progress_print(100.0 * sector_num / total_sectors, 0); } } out: + if (!ret) { + qemu_progress_print(100, 0); + } qemu_progress_end(); free_option_parameters(create_options); free_option_parameters(param); From 049b09825fe479f4caa013ccde0ff87fc9d82856 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 27 Nov 2013 11:07:02 +0100 Subject: [PATCH 38/48] qemu-img: fix usage instruction for qemu-img convert Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Signed-off-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- qemu-img.c | 1 - 1 file changed, 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c index 9d1b6b500a..9fe0ede40b 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -110,7 +110,6 @@ static void help(void) " conversion. If the number of bytes is 0, the source will not be scanned for\n" " unallocated or zero sectors, and the destination image will always be\n" " fully allocated\n" - " images will always be fully allocated\n" " '--output' takes the format in which the output must be done (human or json)\n" " '-n' skips the target volume creation (useful if the volume is created\n" " prior to running qemu-img)\n" From 1c0704a556dbb004a3b82791779760f418053951 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 27 Nov 2013 11:07:03 +0100 Subject: [PATCH 39/48] block/iscsi: set bdi->cluster_size this patch aims to set bdi->cluster_size to the internal page size of the iscsi target so that enabled callers can align requests properly. Reviewed-by: Paolo Bonzini Signed-off-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block/iscsi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 93fee6d1df..75d6b875e4 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1580,6 +1580,13 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) IscsiLun *iscsilun = bs->opaque; bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz; bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws; + /* Guess the internal cluster (page) size of the iscsi target by the means + * of opt_unmap_gran. Transfer the unmap granularity only if it has a + * reasonable size for bdi->cluster_size */ + if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 && + iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) { + bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size; + } return 0; } From 7337acaf219fc988e7ba91780b11770ff95169b4 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 27 Nov 2013 11:07:04 +0100 Subject: [PATCH 40/48] block: add opt_transfer_length to BlockLimits Reviewed-by: Paolo Bonzini Signed-off-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- include/block/block_int.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/block/block_int.h b/include/block/block_int.h index ec0797ebc7..8b132d7178 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -247,6 +247,9 @@ typedef struct BlockLimits { /* optimal alignment for write zeroes requests in sectors */ int64_t write_zeroes_alignment; + + /* optimal transfer length in sectors */ + int opt_transfer_length; } BlockLimits; /* From 7572ddc8db114d8c437a97ca3eaedab397f66cda Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 27 Nov 2013 11:07:05 +0100 Subject: [PATCH 41/48] block/iscsi: set bs->bl.opt_transfer_length Reviewed-by: Paolo Bonzini Signed-off-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- block/iscsi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 75d6b875e4..829d444733 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1457,6 +1457,9 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, } bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran, iscsilun); + + bs->bl.opt_transfer_length = sector_lun2qemu(iscsilun->bl.opt_xfer_len, + iscsilun); } #if defined(LIBISCSI_FEATURE_NOP_COUNTER) From f2521c9023067a007d18b844fe7639c1c5b6f2ac Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 27 Nov 2013 11:07:06 +0100 Subject: [PATCH 42/48] qemu-img: dynamically adjust iobuffer size during convert since the convert process is basically a sync operation it might be benificial in some case to change the hardcoded I/O buffer size to a greater value. This patch increases the I/O buffer size if the output driver advertises an optimal transfer length or discard alignment that is greater than the default buffer size of 2M. Reviewed-by: Paolo Bonzini Signed-off-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- qemu-img.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 9fe0ede40b..0725f22cc2 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1140,6 +1140,7 @@ static int img_convert(int argc, char **argv) sector_num_next_status = 0; uint64_t bs_sectors; uint8_t * buf = NULL; + size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE; const uint8_t *buf1; BlockDriverInfo bdi; QEMUOptionParameter *param = NULL, *create_options = NULL; @@ -1398,7 +1399,16 @@ static int img_convert(int argc, char **argv) bs_i = 0; bs_offset = 0; bdrv_get_geometry(bs[0], &bs_sectors); - buf = qemu_blockalign(out_bs, IO_BUF_SIZE); + + /* increase bufsectors from the default 4096 (2M) if opt_transfer_length + * or discard_alignment of the out_bs is greater. Limit to 32768 (16MB) + * as maximum. */ + bufsectors = MIN(32768, + MAX(bufsectors, MAX(out_bs->bl.opt_transfer_length, + out_bs->bl.discard_alignment)) + ); + + buf = qemu_blockalign(out_bs, bufsectors * BDRV_SECTOR_SIZE); if (skip_create) { int64_t output_length = bdrv_getlength(out_bs); @@ -1421,7 +1431,7 @@ static int img_convert(int argc, char **argv) goto out; } cluster_size = bdi.cluster_size; - if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) { + if (cluster_size <= 0 || cluster_size > bufsectors * BDRV_SECTOR_SIZE) { error_report("invalid cluster size"); ret = -1; goto out; @@ -1558,7 +1568,7 @@ static int img_convert(int argc, char **argv) sector_num_next_status = sector_num + n1; } - n = MIN(nb_sectors, IO_BUF_SIZE / 512); + n = MIN(nb_sectors, bufsectors); n = MIN(n, bs_sectors - (sector_num - bs_offset)); n1 = n; From 24f833cd43dbfb5f8ae99e8a6d3691671622d3ea Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 27 Nov 2013 11:07:07 +0100 Subject: [PATCH 43/48] qemu-img: round down request length to an aligned sector this patch shortens requests to end at an aligned sector so that the next request starts aligned. [Squashed Peter's fix for bdrv_get_info() failure discussed on the mailing list. --Stefan] Reviewed-by: Paolo Bonzini Signed-off-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- qemu-img.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 0725f22cc2..76f05f2e94 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1129,8 +1129,7 @@ out3: static int img_convert(int argc, char **argv) { - int c, n, n1, bs_n, bs_i, compress, cluster_size, - cluster_sectors, skip_create; + int c, n, n1, bs_n, bs_i, compress, cluster_sectors, skip_create; int64_t ret = 0; int progress = 0, flags; const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename; @@ -1424,19 +1423,23 @@ static int img_convert(int argc, char **argv) } } - if (compress) { - ret = bdrv_get_info(out_bs, &bdi); - if (ret < 0) { + cluster_sectors = 0; + ret = bdrv_get_info(out_bs, &bdi); + if (ret < 0) { + if (compress) { error_report("could not get block driver info"); goto out; } - cluster_size = bdi.cluster_size; - if (cluster_size <= 0 || cluster_size > bufsectors * BDRV_SECTOR_SIZE) { + } else { + cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; + } + + if (compress) { + if (cluster_sectors <= 0 || cluster_sectors > bufsectors) { error_report("invalid cluster size"); ret = -1; goto out; } - cluster_sectors = cluster_size >> 9; sector_num = 0; nb_sectors = total_sectors; @@ -1569,6 +1572,19 @@ static int img_convert(int argc, char **argv) } n = MIN(nb_sectors, bufsectors); + + /* round down request length to an aligned sector, but + * do not bother doing this on short requests. They happen + * when we found an all-zero area, and the next sector to + * write will not be sector_num + n. */ + if (cluster_sectors > 0 && n >= cluster_sectors) { + int64_t next_aligned_sector = (sector_num + n); + next_aligned_sector -= next_aligned_sector % cluster_sectors; + if (sector_num + n > next_aligned_sector) { + n = next_aligned_sector - sector_num; + } + } + n = MIN(n, bs_sectors - (sector_num - bs_offset)); n1 = n; From 405889820bcd5c2abf4eb70598e96f525f862c0f Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 27 Nov 2013 11:07:09 +0100 Subject: [PATCH 44/48] qemu-img: decrease progress update interval on convert when doing very large jobs updating the progress only every 2% is too rare. Signed-off-by: Peter Lieven Signed-off-by: Stefan Hajnoczi --- qemu-img.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c index 76f05f2e94..7dfe982b0c 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1245,7 +1245,7 @@ static int img_convert(int argc, char **argv) out_filename = argv[argc - 1]; /* Initialize before goto out */ - qemu_progress_init(progress, 2.0); + qemu_progress_init(progress, 1.0); if (options && is_help_option(options)) { ret = print_block_option_help(out_filename, out_fmt); From ac95acdb8e0876fa489bd31a48e8ecd6ef901d67 Mon Sep 17 00:00:00 2001 From: Hu Tao Date: Thu, 5 Dec 2013 14:32:34 +0800 Subject: [PATCH 45/48] qcow2: use start_of_cluster() and offset_into_cluster() everywhere Signed-off-by: Hu Tao Reviewed-by: Fam Zheng Signed-off-by: Stefan Hajnoczi --- block/qcow2-cluster.c | 2 +- block/qcow2-refcount.c | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 11f9c50aa7..853408438a 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1401,7 +1401,7 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset, /* Round start up and end down */ offset = align_offset(offset, s->cluster_size); - end_offset &= ~(s->cluster_size - 1); + end_offset = start_of_cluster(s, end_offset); if (offset > end_offset) { return 0; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 1ff43d0906..c974abe795 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -515,8 +515,8 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, s->l2_table_cache); } - start = offset & ~(s->cluster_size - 1); - last = (offset + length - 1) & ~(s->cluster_size - 1); + start = start_of_cluster(s, offset); + last = start_of_cluster(s, offset + length - 1); for(cluster_offset = start; cluster_offset <= last; cluster_offset += s->cluster_size) { @@ -724,7 +724,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) } redo: free_in_cluster = s->cluster_size - - (s->free_byte_offset & (s->cluster_size - 1)); + offset_into_cluster(s, s->free_byte_offset); if (size <= free_in_cluster) { /* enough space in current cluster */ offset = s->free_byte_offset; @@ -732,7 +732,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) free_in_cluster -= size; if (free_in_cluster == 0) s->free_byte_offset = 0; - if ((offset & (s->cluster_size - 1)) != 0) + if (offset_into_cluster(s, offset) != 0) qcow2_update_cluster_refcount(bs, offset >> s->cluster_bits, 1, QCOW2_DISCARD_NEVER); } else { @@ -740,7 +740,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) if (offset < 0) { return offset; } - cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1); + cluster_offset = start_of_cluster(s, s->free_byte_offset); if ((cluster_offset + s->cluster_size) == offset) { /* we are lucky: contiguous data */ offset = s->free_byte_offset; @@ -1010,8 +1010,8 @@ static void inc_refcounts(BlockDriverState *bs, if (size <= 0) return; - start = offset & ~(s->cluster_size - 1); - last = (offset + size - 1) & ~(s->cluster_size - 1); + start = start_of_cluster(s, offset); + last = start_of_cluster(s, offset + size - 1); for(cluster_offset = start; cluster_offset <= last; cluster_offset += s->cluster_size) { k = cluster_offset >> s->cluster_bits; @@ -1122,7 +1122,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, offset, s->cluster_size); /* Correct offsets are cluster aligned */ - if (offset & (s->cluster_size - 1)) { + if (offset_into_cluster(s, offset)) { fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not " "properly aligned; L2 entry corrupted.\n", offset); res->corruptions++; @@ -1194,7 +1194,7 @@ static int check_refcounts_l1(BlockDriverState *bs, l2_offset, s->cluster_size); /* L2 tables are cluster aligned */ - if (l2_offset & (s->cluster_size - 1)) { + if (offset_into_cluster(s, l2_offset)) { fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not " "cluster aligned; L1 entry corrupted\n", l2_offset); res->corruptions++; @@ -1423,7 +1423,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index, } /* update refcount table */ - assert(!(new_offset & (s->cluster_size - 1))); + assert(!offset_into_cluster(s, new_offset)); s->refcount_table[reftable_index] = new_offset; ret = write_reftable_entry(bs, reftable_index); if (ret < 0) { @@ -1507,7 +1507,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, cluster = offset >> s->cluster_bits; /* Refcount blocks are cluster aligned */ - if (offset & (s->cluster_size - 1)) { + if (offset_into_cluster(s, offset)) { fprintf(stderr, "ERROR refcount block %" PRId64 " is not " "cluster aligned; refcount table entry corrupted\n", i); res->corruptions++; From 0b06ef3bdd17742ae50c0662d3fe8ed944648890 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 26 Nov 2013 16:18:00 +0100 Subject: [PATCH 46/48] block: clean up bdrv_drain_all() throttling comments Since cc0681c45430a1f1a4c2d06e9499b7775afc9a18 ("block: Enable the new throttling code in the block layer.") bdrv_drain_all() no longer spins. The code used to look as follows: do { busy = qemu_aio_wait(); /* FIXME: We do not have timer support here, so this is effectively * a busy wait. */ QTAILQ_FOREACH(bs, &bdrv_states, list) { while (qemu_co_enter_next(&bs->throttled_reqs)) { busy = true; } } } while (busy); Note that throttle requests are kicked but I/O throttling limits are still in effect. The loop spins until the vm_clock time allows the request to make progress and complete. The new throttling code introduced bdrv_start_throttled_reqs(). This function not only kicks throttled requests but also temporarily disables throttling so requests can run. The outdated FIXME comment can be removed. Also drop the busy = true assignment since we overwrite it immediately afterwards. Reviewed-by: Alex Bligh Signed-off-by: Stefan Hajnoczi --- block.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/block.c b/block.c index 1c83ef1fab..13f001ad69 100644 --- a/block.c +++ b/block.c @@ -1557,13 +1557,8 @@ void bdrv_drain_all(void) BlockDriverState *bs; while (busy) { - /* FIXME: We do not have timer support here, so this is effectively - * a busy wait. - */ QTAILQ_FOREACH(bs, &bdrv_states, list) { - if (bdrv_start_throttled_reqs(bs)) { - busy = true; - } + bdrv_start_throttled_reqs(bs); } busy = bdrv_requests_pending_all(); From d3fa923044321b2ccc12bbdedd582d2c49d958aa Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 26 Nov 2013 16:18:01 +0100 Subject: [PATCH 47/48] aio: make aio_poll(ctx, true) block with no fds This patch drops a special case where aio_poll(ctx, true) returns false instead of blocking if no file descriptors are waiting on I/O. Now it is possible to block in aio_poll() to wait for aio_notify(). This change eliminates busy waiting. bdrv_drain_all() used to rely on busy waiting to completed throttled I/O requests but this is no longer required so we can simplify aio_poll(). Note that aio_poll() still returns false when aio_notify() was used. In other words, stopping a blocking aio_poll() wait is not considered making progress. Adjust test-aio /aio/bh/callback-delete/one which assumed aio_poll(ctx, true) would immediately return false instead of blocking. Reviewed-by: Alex Bligh Signed-off-by: Stefan Hajnoczi --- aio-posix.c | 5 ----- aio-win32.c | 5 ----- tests/test-aio.c | 1 - 3 files changed, 11 deletions(-) diff --git a/aio-posix.c b/aio-posix.c index bd06f33c78..f921d4f538 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -217,11 +217,6 @@ bool aio_poll(AioContext *ctx, bool blocking) ctx->walking_handlers--; - /* early return if we only have the aio_notify() fd */ - if (ctx->pollfds->len == 1) { - return progress; - } - /* wait until next event */ ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data, ctx->pollfds->len, diff --git a/aio-win32.c b/aio-win32.c index f9cfbb75ac..23f4e5ba19 100644 --- a/aio-win32.c +++ b/aio-win32.c @@ -161,11 +161,6 @@ bool aio_poll(AioContext *ctx, bool blocking) ctx->walking_handlers--; - /* early return if we only have the aio_notify() fd */ - if (count == 1) { - return progress; - } - /* wait until next event */ while (count > 0) { int ret; diff --git a/tests/test-aio.c b/tests/test-aio.c index c4fe0fc3b7..592721ed3f 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -195,7 +195,6 @@ static void test_bh_delete_from_cb(void) g_assert(data1.bh == NULL); g_assert(!aio_poll(ctx, false)); - g_assert(!aio_poll(ctx, true)); } static void test_bh_delete_from_cb_many(void) From ac9524dc55dc32e492ac3e6fbc9785be7168f8a2 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 14 Nov 2013 15:24:58 +0100 Subject: [PATCH 48/48] qemu-iotests: filter QEMU monitor \r\n SMTP does not preserve newlines. This is normally not a problem if the email body uses DOS or UNIX newlines consistently. In 051.out we mix UNIX newlines with DOS newlines (since QEMU monitor output uses \r\n). This patch filters the QEMU monitor output so the golden master file uses UNIX newlines exclusively. The result is that patches touching 051.out will apply cleanly without mangling newlines after this commit. Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/051.out | 112 +++++++++++++++---------------- tests/qemu-iotests/common.filter | 3 +- 2 files changed, 58 insertions(+), 57 deletions(-) diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index ddef87cb18..49e95a20cf 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -39,12 +39,12 @@ ide0-hd0: TEST_DIR/t.qcow2 (qcow2) === Enable and disable lazy refcounting on the command line, plus some invalid values === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts= QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off' @@ -63,71 +63,71 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: could not open disk image TEST_DIR/t.qcow2: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit === No medium === Testing: -drive if=floppy -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive if=ide,media=cdrom -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive if=scsi,media=cdrom -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive if=ide -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: Device needs media, but drive is empty QEMU_PROG: Device initialization failed. QEMU_PROG: Initialization of device ide-hd failed Testing: -drive if=virtio -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty QEMU_PROG: -drive if=virtio: Device initialization failed. QEMU_PROG: -drive if=virtio: Device initialization failed. QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized Testing: -drive if=scsi -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty QEMU_PROG: Device initialization failed. QEMU_PROG: Initialization of device lsi53c895a failed Testing: -drive if=none,id=disk -device ide-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive if=none,id=disk -device ide-drive,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized Testing: -drive if=none,id=disk -device ide-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty QEMU_PROG: -device scsi-disk,drive=disk: Device initialization failed. QEMU_PROG: -device scsi-disk,drive=disk: Device 'scsi-disk' could not be initialized Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty QEMU_PROG: -device scsi-hd,drive=disk: Device initialization failed. QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized @@ -136,81 +136,81 @@ QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized === Read-only === Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: Can't use a read-only drive QEMU_PROG: Device initialization failed. QEMU_PROG: Initialization of device ide-hd failed Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information +QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit === Cache modes === Testing: -drive media=cdrom,cache=none -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive media=cdrom,cache=directsync -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive media=cdrom,cache=writeback -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive media=cdrom,cache=writethrough -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive media=cdrom,cache=unsafe -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive media=cdrom,cache=invalid_value QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option @@ -219,8 +219,8 @@ QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option === Specifying the protocol layer === Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2 QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Can't use 'qcow2' as a block driver for the protocol level diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 9c82c77a81..776985d15e 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -157,7 +157,8 @@ _filter_qemu_io() _filter_qemu() { sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ - -e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' + -e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \ + -e $'s#\r##' # QEMU monitor uses \r\n line endings } # replace problematic QMP output like timestamps