1
Merge remote-tracking branch 'remotes/edgar/tags/edgar/xilinx-next-2018-05-29-v1.for-upstream' into staging (2018-05-29 13:01:11 +0100)
1
The following changes since commit 281f327487c9c9b1599f93c589a408bbf4a651b8:
2
3
Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.12-pull-request' into staging (2017-12-22 00:11:36 +0000)
2
4
3
are available in the git repository at:
5
are available in the git repository at:
4
6
5
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
6
8
7
for you to fetch changes up to 3fb588a0f2c006122c34e1960a15c87ae2b927eb:
9
for you to fetch changes up to 1a63a907507fbbcfaee3f622907ec244b7eabda8:
8
10
9
block/create: Mark blockdev-create stable (2018-05-30 13:31:18 +0200)
11
block: Keep nodes drained between reopen_queue/multiple (2017-12-22 15:05:32 +0100)
10
12
11
----------------------------------------------------------------
13
----------------------------------------------------------------
12
Block layer patches:
14
Block layer patches
13
14
- Add blockdev-create job
15
- qcow2: Silence Coverity false positive
16
15
17
----------------------------------------------------------------
16
----------------------------------------------------------------
18
Alberto Garcia (1):
17
Doug Gale (1):
19
qcow2: Fix Coverity warning when calculating the refcount cache size
18
nvme: Add tracing
20
19
21
Kevin Wolf (16):
20
Edgar Kaziakhmedov (1):
22
vdi: Fix vdi_co_do_create() return value
21
qcow2: get rid of qcow2_backing_read1 routine
23
vhdx: Fix vhdx_co_create() return value
24
job: Add error message for failing jobs
25
block/create: Make x-blockdev-create a job
26
qemu-iotests: Add VM.get_qmp_events_filtered()
27
qemu-iotests: Add VM.qmp_log()
28
qemu-iotests: Add iotests.img_info_log()
29
qemu-iotests: Add VM.run_job()
30
qemu-iotests: iotests.py helper for non-file protocols
31
qemu-iotests: Rewrite 206 for blockdev-create job
32
qemu-iotests: Rewrite 207 for blockdev-create job
33
qemu-iotests: Rewrite 210 for blockdev-create job
34
qemu-iotests: Rewrite 211 for blockdev-create job
35
qemu-iotests: Rewrite 212 for blockdev-create job
36
qemu-iotests: Rewrite 213 for blockdev-create job
37
block/create: Mark blockdev-create stable
38
22
39
qapi/block-core.json | 18 +-
23
Fam Zheng (2):
40
qapi/job.json | 4 +-
24
block: Open backing image in force share mode for size probe
41
include/qemu/job.h | 7 +-
25
block: Remove unused bdrv_requests_pending
42
block/backup.c | 2 +-
43
block/commit.c | 2 +-
44
block/create.c | 67 +++--
45
block/mirror.c | 2 +-
46
block/qcow2.c | 5 +-
47
block/stream.c | 2 +-
48
block/vdi.c | 1 +
49
block/vhdx.c | 2 +-
50
job-qmp.c | 9 +-
51
job.c | 16 +-
52
tests/test-bdrv-drain.c | 2 +-
53
tests/test-blockjob-txn.c | 2 +-
54
tests/test-blockjob.c | 2 +-
55
tests/qemu-iotests/206 | 680 ++++++++++++++++--------------------------
56
tests/qemu-iotests/206.out | 253 +++++++++-------
57
tests/qemu-iotests/207 | 440 ++++++++++++---------------
58
tests/qemu-iotests/207.out | 107 +++----
59
tests/qemu-iotests/210 | 393 ++++++++++--------------
60
tests/qemu-iotests/210.out | 197 ++++++++----
61
tests/qemu-iotests/211 | 381 ++++++++++-------------
62
tests/qemu-iotests/211.out | 133 +++++----
63
tests/qemu-iotests/212 | 483 +++++++++++-------------------
64
tests/qemu-iotests/212.out | 191 +++++++-----
65
tests/qemu-iotests/213 | 520 ++++++++++++--------------------
66
tests/qemu-iotests/213.out | 208 ++++++++-----
67
tests/qemu-iotests/iotests.py | 78 +++++
68
29 files changed, 1981 insertions(+), 2226 deletions(-)
69
26
27
John Snow (1):
28
iotests: fix 197 for vpc
29
30
Kevin Wolf (27):
31
block: Formats don't need CONSISTENT_READ with NO_IO
32
block: Make bdrv_drain_invoke() recursive
33
block: Call .drain_begin only once in bdrv_drain_all_begin()
34
test-bdrv-drain: Test BlockDriver callbacks for drain
35
block: bdrv_drain_recurse(): Remove unused begin parameter
36
block: Don't wait for requests in bdrv_drain*_end()
37
block: Unify order in drain functions
38
block: Don't acquire AioContext in hmp_qemu_io()
39
block: Document that x-blockdev-change breaks quorum children list
40
block: Assert drain_all is only called from main AioContext
41
block: Make bdrv_drain() driver callbacks non-recursive
42
test-bdrv-drain: Test callback for bdrv_drain
43
test-bdrv-drain: Test bs->quiesce_counter
44
blockjob: Pause job on draining any job BDS
45
test-bdrv-drain: Test drain vs. block jobs
46
block: Don't block_job_pause_all() in bdrv_drain_all()
47
block: Nested drain_end must still call callbacks
48
test-bdrv-drain: Test nested drain sections
49
block: Don't notify parents in drain call chain
50
block: Add bdrv_subtree_drained_begin/end()
51
test-bdrv-drain: Tests for bdrv_subtree_drain
52
test-bdrv-drain: Test behaviour in coroutine context
53
test-bdrv-drain: Recursive draining with multiple parents
54
block: Allow graph changes in subtree drained section
55
test-bdrv-drain: Test graph changes in drained section
56
commit: Simplify reopen of base
57
block: Keep nodes drained between reopen_queue/multiple
58
59
Thomas Huth (3):
60
block: Remove the obsolete -drive boot=on|off parameter
61
block: Remove the deprecated -hdachs option
62
block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter
63
64
qapi/block-core.json | 4 +
65
block/qcow2.h | 3 -
66
include/block/block.h | 15 +-
67
include/block/block_int.h | 6 +-
68
block.c | 75 ++++-
69
block/commit.c | 8 +-
70
block/io.c | 164 +++++++---
71
block/qcow2.c | 51 +--
72
block/replication.c | 6 +
73
blockdev.c | 11 -
74
blockjob.c | 22 +-
75
hmp.c | 6 -
76
hw/block/nvme.c | 349 +++++++++++++++++----
77
qemu-io-cmds.c | 3 +
78
tests/test-bdrv-drain.c | 651 +++++++++++++++++++++++++++++++++++++++
79
vl.c | 86 +-----
80
hw/block/trace-events | 93 ++++++
81
qemu-doc.texi | 29 +-
82
qemu-options.hx | 19 +-
83
tests/Makefile.include | 2 +
84
tests/qemu-iotests/197 | 4 +
85
tests/qemu-iotests/common.filter | 3 +-
86
22 files changed, 1294 insertions(+), 316 deletions(-)
87
create mode 100644 tests/test-bdrv-drain.c
88
diff view generated by jsdifflib
New patch
1
Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently
2
in use as a mirror target. It is not enough for image formats, though,
3
as these still unconditionally request BLK_PERM_CONSISTENT_READ.
1
4
5
As this permission is geared towards whether the guest-visible data is
6
consistent, and has no impact on whether the metadata is sane, and
7
'qemu-img info' does not read guest-visible data (except for the raw
8
format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there
9
is not going to be any guest I/O performed, regardless of image format.
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block.c | 6 +++++-
14
1 file changed, 5 insertions(+), 1 deletion(-)
15
16
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
19
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
21
assert(role == &child_backing || role == &child_file);
22
23
if (!backing) {
24
+ int flags = bdrv_reopen_get_flags(reopen_queue, bs);
25
+
26
/* Apart from the modifications below, the same permissions are
27
* forwarded and left alone as for filters */
28
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
29
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
30
31
/* bs->file always needs to be consistent because of the metadata. We
32
* can never allow other users to resize or write to it. */
33
- perm |= BLK_PERM_CONSISTENT_READ;
34
+ if (!(flags & BDRV_O_NO_IO)) {
35
+ perm |= BLK_PERM_CONSISTENT_READ;
36
+ }
37
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
38
} else {
39
/* We want consistent read from backing files if the parent needs it.
40
--
41
2.13.6
42
43
diff view generated by jsdifflib
New patch
1
From: John Snow <jsnow@redhat.com>
1
2
3
VPC has some difficulty creating geometries of particular size.
4
However, we can indeed force it to use a literal one, so let's
5
do that for the sake of test 197, which is testing some specific
6
offsets.
7
8
Signed-off-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Lukáš Doktor <ldoktor@redhat.com>
13
---
14
tests/qemu-iotests/197 | 4 ++++
15
tests/qemu-iotests/common.filter | 3 ++-
16
2 files changed, 6 insertions(+), 1 deletion(-)
17
18
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/197
21
+++ b/tests/qemu-iotests/197
22
@@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ==='
23
echo
24
25
# Prep the images
26
+# VPC rounds image sizes to a specific geometry, force a specific size.
27
+if [ "$IMGFMT" = "vpc" ]; then
28
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
29
+fi
30
_make_test_img 4G
31
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
32
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
33
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
34
index XXXXXXX..XXXXXXX 100644
35
--- a/tests/qemu-iotests/common.filter
36
+++ b/tests/qemu-iotests/common.filter
37
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
38
-e "s# log_size=[0-9]\\+##g" \
39
-e "s# refcount_bits=[0-9]\\+##g" \
40
-e "s# key-secret=[a-zA-Z0-9]\\+##g" \
41
- -e "s# iter-time=[0-9]\\+##g"
42
+ -e "s# iter-time=[0-9]\\+##g" \
43
+ -e "s# force_size=\\(on\\|off\\)##g"
44
}
45
46
_filter_img_info()
47
--
48
2.13.6
49
50
diff view generated by jsdifflib
New patch
1
This change separates bdrv_drain_invoke(), which calls the BlockDriver
2
drain callbacks, from bdrv_drain_recurse(). Instead, the function
3
performs its own recursion now.
1
4
5
One reason for this is that bdrv_drain_recurse() can be called multiple
6
times by bdrv_drain_all_begin(), but the callbacks may only be called
7
once. The separation is necessary to fix this bug.
8
9
The other reason is that we intend to go to a model where we call all
10
driver callbacks first, and only then start polling. This is not fully
11
achieved yet with this patch, as bdrv_drain_invoke() contains a
12
BDRV_POLL_WHILE() loop for the block driver callbacks, which can still
13
call callbacks for any unrelated event. It's a step in this direction
14
anyway.
15
16
Cc: qemu-stable@nongnu.org
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
19
---
20
block/io.c | 14 +++++++++++---
21
1 file changed, 11 insertions(+), 3 deletions(-)
22
23
diff --git a/block/io.c b/block/io.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/io.c
26
+++ b/block/io.c
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
28
bdrv_wakeup(bs);
29
}
30
31
+/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
32
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
33
{
34
+ BdrvChild *child, *tmp;
35
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
36
37
if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) ||
38
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
39
data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data);
40
bdrv_coroutine_enter(bs, data.co);
41
BDRV_POLL_WHILE(bs, !data.done);
42
+
43
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
44
+ bdrv_drain_invoke(child->bs, begin);
45
+ }
46
}
47
48
static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
49
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
50
BdrvChild *child, *tmp;
51
bool waited;
52
53
- /* Ensure any pending metadata writes are submitted to bs->file. */
54
- bdrv_drain_invoke(bs, begin);
55
-
56
/* Wait for drained requests to finish */
57
waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
58
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
60
bdrv_parent_drained_begin(bs);
61
}
62
63
+ bdrv_drain_invoke(bs, true);
64
bdrv_drain_recurse(bs, true);
65
}
66
67
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
68
}
69
70
bdrv_parent_drained_end(bs);
71
+ bdrv_drain_invoke(bs, false);
72
bdrv_drain_recurse(bs, false);
73
aio_enable_external(bdrv_get_aio_context(bs));
74
}
75
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
76
aio_context_acquire(aio_context);
77
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
78
if (aio_context == bdrv_get_aio_context(bs)) {
79
+ /* FIXME Calling this multiple times is wrong */
80
+ bdrv_drain_invoke(bs, true);
81
waited |= bdrv_drain_recurse(bs, true);
82
}
83
}
84
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
85
aio_context_acquire(aio_context);
86
aio_enable_external(aio_context);
87
bdrv_parent_drained_end(bs);
88
+ bdrv_drain_invoke(bs, false);
89
bdrv_drain_recurse(bs, false);
90
aio_context_release(aio_context);
91
}
92
--
93
2.13.6
94
95
diff view generated by jsdifflib
New patch
1
bdrv_drain_all_begin() used to call the .bdrv_co_drain_begin() driver
2
callback inside its polling loop. This means that how many times it got
3
called for each node depended on long it had to poll the event loop.
1
4
5
This is obviously not right and results in nodes that stay drained even
6
after bdrv_drain_all_end(), which calls .bdrv_co_drain_begin() once per
7
node.
8
9
Fix bdrv_drain_all_begin() to call the callback only once, too.
10
11
Cc: qemu-stable@nongnu.org
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
15
block/io.c | 3 +--
16
1 file changed, 1 insertion(+), 2 deletions(-)
17
18
diff --git a/block/io.c b/block/io.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/io.c
21
+++ b/block/io.c
22
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
23
aio_context_acquire(aio_context);
24
bdrv_parent_drained_begin(bs);
25
aio_disable_external(aio_context);
26
+ bdrv_drain_invoke(bs, true);
27
aio_context_release(aio_context);
28
29
if (!g_slist_find(aio_ctxs, aio_context)) {
30
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
31
aio_context_acquire(aio_context);
32
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
33
if (aio_context == bdrv_get_aio_context(bs)) {
34
- /* FIXME Calling this multiple times is wrong */
35
- bdrv_drain_invoke(bs, true);
36
waited |= bdrv_drain_recurse(bs, true);
37
}
38
}
39
--
40
2.13.6
41
42
diff view generated by jsdifflib
New patch
1
This adds a test case that the BlockDriver callbacks for drain are
2
called in bdrv_drained_all_begin/end(), and that both of them are called
3
exactly once.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
9
tests/test-bdrv-drain.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++
10
tests/Makefile.include | 2 +
11
2 files changed, 139 insertions(+)
12
create mode 100644 tests/test-bdrv-drain.c
13
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
15
new file mode 100644
16
index XXXXXXX..XXXXXXX
17
--- /dev/null
18
+++ b/tests/test-bdrv-drain.c
19
@@ -XXX,XX +XXX,XX @@
20
+/*
21
+ * Block node draining tests
22
+ *
23
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
24
+ *
25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
26
+ * of this software and associated documentation files (the "Software"), to deal
27
+ * in the Software without restriction, including without limitation the rights
28
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29
+ * copies of the Software, and to permit persons to whom the Software is
30
+ * furnished to do so, subject to the following conditions:
31
+ *
32
+ * The above copyright notice and this permission notice shall be included in
33
+ * all copies or substantial portions of the Software.
34
+ *
35
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41
+ * THE SOFTWARE.
42
+ */
43
+
44
+#include "qemu/osdep.h"
45
+#include "block/block.h"
46
+#include "sysemu/block-backend.h"
47
+#include "qapi/error.h"
48
+
49
+typedef struct BDRVTestState {
50
+ int drain_count;
51
+} BDRVTestState;
52
+
53
+static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
54
+{
55
+ BDRVTestState *s = bs->opaque;
56
+ s->drain_count++;
57
+}
58
+
59
+static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
60
+{
61
+ BDRVTestState *s = bs->opaque;
62
+ s->drain_count--;
63
+}
64
+
65
+static void bdrv_test_close(BlockDriverState *bs)
66
+{
67
+ BDRVTestState *s = bs->opaque;
68
+ g_assert_cmpint(s->drain_count, >, 0);
69
+}
70
+
71
+static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
72
+ uint64_t offset, uint64_t bytes,
73
+ QEMUIOVector *qiov, int flags)
74
+{
75
+ /* We want this request to stay until the polling loop in drain waits for
76
+ * it to complete. We need to sleep a while as bdrv_drain_invoke() comes
77
+ * first and polls its result, too, but it shouldn't accidentally complete
78
+ * this request yet. */
79
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
80
+
81
+ return 0;
82
+}
83
+
84
+static BlockDriver bdrv_test = {
85
+ .format_name = "test",
86
+ .instance_size = sizeof(BDRVTestState),
87
+
88
+ .bdrv_close = bdrv_test_close,
89
+ .bdrv_co_preadv = bdrv_test_co_preadv,
90
+
91
+ .bdrv_co_drain_begin = bdrv_test_co_drain_begin,
92
+ .bdrv_co_drain_end = bdrv_test_co_drain_end,
93
+};
94
+
95
+static void aio_ret_cb(void *opaque, int ret)
96
+{
97
+ int *aio_ret = opaque;
98
+ *aio_ret = ret;
99
+}
100
+
101
+static void test_drv_cb_drain_all(void)
102
+{
103
+ BlockBackend *blk;
104
+ BlockDriverState *bs;
105
+ BDRVTestState *s;
106
+ BlockAIOCB *acb;
107
+ int aio_ret;
108
+
109
+ QEMUIOVector qiov;
110
+ struct iovec iov = {
111
+ .iov_base = NULL,
112
+ .iov_len = 0,
113
+ };
114
+ qemu_iovec_init_external(&qiov, &iov, 1);
115
+
116
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
117
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
118
+ &error_abort);
119
+ s = bs->opaque;
120
+ blk_insert_bs(blk, bs, &error_abort);
121
+
122
+ /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */
123
+ g_assert_cmpint(s->drain_count, ==, 0);
124
+ bdrv_drain_all_begin();
125
+ g_assert_cmpint(s->drain_count, ==, 1);
126
+ bdrv_drain_all_end();
127
+ g_assert_cmpint(s->drain_count, ==, 0);
128
+
129
+ /* Now do the same while a request is pending */
130
+ aio_ret = -EINPROGRESS;
131
+ acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret);
132
+ g_assert(acb != NULL);
133
+ g_assert_cmpint(aio_ret, ==, -EINPROGRESS);
134
+
135
+ g_assert_cmpint(s->drain_count, ==, 0);
136
+ bdrv_drain_all_begin();
137
+ g_assert_cmpint(aio_ret, ==, 0);
138
+ g_assert_cmpint(s->drain_count, ==, 1);
139
+ bdrv_drain_all_end();
140
+ g_assert_cmpint(s->drain_count, ==, 0);
141
+
142
+ bdrv_unref(bs);
143
+ blk_unref(blk);
144
+}
145
+
146
+int main(int argc, char **argv)
147
+{
148
+ bdrv_init();
149
+ qemu_init_main_loop(&error_abort);
150
+
151
+ g_test_init(&argc, &argv, NULL);
152
+
153
+ g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
154
+
155
+ return g_test_run();
156
+}
157
diff --git a/tests/Makefile.include b/tests/Makefile.include
158
index XXXXXXX..XXXXXXX 100644
159
--- a/tests/Makefile.include
160
+++ b/tests/Makefile.include
161
@@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c
162
gcov-files-test-hbitmap-y = util/hbitmap.c
163
check-unit-y += tests/test-hbitmap$(EXESUF)
164
gcov-files-test-hbitmap-y = blockjob.c
165
+check-unit-y += tests/test-bdrv-drain$(EXESUF)
166
check-unit-y += tests/test-blockjob$(EXESUF)
167
check-unit-y += tests/test-blockjob-txn$(EXESUF)
168
check-unit-y += tests/test-x86-cpuid$(EXESUF)
169
@@ -XXX,XX +XXX,XX @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
170
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
171
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
172
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
173
+tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
174
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
175
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
176
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
177
--
178
2.13.6
179
180
diff view generated by jsdifflib
New patch
1
Now that the bdrv_drain_invoke() calls are pulled up to the callers of
2
bdrv_drain_recurse(), the 'begin' parameter isn't needed any more.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/io.c | 12 ++++++------
8
1 file changed, 6 insertions(+), 6 deletions(-)
9
10
diff --git a/block/io.c b/block/io.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/io.c
13
+++ b/block/io.c
14
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
15
}
16
}
17
18
-static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
19
+static bool bdrv_drain_recurse(BlockDriverState *bs)
20
{
21
BdrvChild *child, *tmp;
22
bool waited;
23
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
24
*/
25
bdrv_ref(bs);
26
}
27
- waited |= bdrv_drain_recurse(bs, begin);
28
+ waited |= bdrv_drain_recurse(bs);
29
if (in_main_loop) {
30
bdrv_unref(bs);
31
}
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
33
}
34
35
bdrv_drain_invoke(bs, true);
36
- bdrv_drain_recurse(bs, true);
37
+ bdrv_drain_recurse(bs);
38
}
39
40
void bdrv_drained_end(BlockDriverState *bs)
41
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
42
43
bdrv_parent_drained_end(bs);
44
bdrv_drain_invoke(bs, false);
45
- bdrv_drain_recurse(bs, false);
46
+ bdrv_drain_recurse(bs);
47
aio_enable_external(bdrv_get_aio_context(bs));
48
}
49
50
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
51
aio_context_acquire(aio_context);
52
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
53
if (aio_context == bdrv_get_aio_context(bs)) {
54
- waited |= bdrv_drain_recurse(bs, true);
55
+ waited |= bdrv_drain_recurse(bs);
56
}
57
}
58
aio_context_release(aio_context);
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
60
aio_enable_external(aio_context);
61
bdrv_parent_drained_end(bs);
62
bdrv_drain_invoke(bs, false);
63
- bdrv_drain_recurse(bs, false);
64
+ bdrv_drain_recurse(bs);
65
aio_context_release(aio_context);
66
}
67
68
--
69
2.13.6
70
71
diff view generated by jsdifflib
1
Add an iotests.py function that runs a job and only returns when it is
1
The device is drained, so there is no point in waiting for requests at
2
destroyed. An error is logged when the job failed and job-finalize and
2
the end of the drained section. Remove the bdrv_drain_recurse() calls
3
job-dismiss commands are issued if necessary.
3
there.
4
5
The bdrv_drain_recurse() calls were introduced in commit 481cad48e5e
6
in order to call the .bdrv_co_drain_end() driver callback. This is now
7
done by a separate bdrv_drain_invoke() call.
4
8
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
7
Reviewed-by: Jeff Cody <jcody@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
12
---
9
tests/qemu-iotests/iotests.py | 19 +++++++++++++++++++
13
block/io.c | 2 --
10
1 file changed, 19 insertions(+)
14
1 file changed, 2 deletions(-)
11
15
12
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
16
diff --git a/block/io.c b/block/io.c
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/iotests.py
18
--- a/block/io.c
15
+++ b/tests/qemu-iotests/iotests.py
19
+++ b/block/io.c
16
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
20
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
17
log(str(result), filters)
21
18
return result
22
bdrv_parent_drained_end(bs);
19
23
bdrv_drain_invoke(bs, false);
20
+ def run_job(self, job, auto_finalize=True, auto_dismiss=False):
24
- bdrv_drain_recurse(bs);
21
+ while True:
25
aio_enable_external(bdrv_get_aio_context(bs));
22
+ for ev in self.get_qmp_events_filtered(wait=True):
26
}
23
+ if ev['event'] == 'JOB_STATUS_CHANGE':
27
24
+ status = ev['data']['status']
28
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
25
+ if status == 'aborting':
29
aio_enable_external(aio_context);
26
+ result = self.qmp('query-jobs')
30
bdrv_parent_drained_end(bs);
27
+ for j in result['return']:
31
bdrv_drain_invoke(bs, false);
28
+ if j['id'] == job:
32
- bdrv_drain_recurse(bs);
29
+ log('Job failed: %s' % (j['error']))
33
aio_context_release(aio_context);
30
+ elif status == 'pending' and not auto_finalize:
34
}
31
+ self.qmp_log('job-finalize', id=job)
32
+ elif status == 'concluded' and not auto_dismiss:
33
+ self.qmp_log('job-dismiss', id=job)
34
+ elif status == 'null':
35
+ return
36
+ else:
37
+ iotests.log(ev)
38
+
39
40
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
41
35
42
--
36
--
43
2.13.6
37
2.13.6
44
38
45
39
diff view generated by jsdifflib
1
This adds a helper function that logs both the QMP request and the
1
Drain requests are propagated to child nodes, parent nodes and directly
2
received response before returning it.
2
to the AioContext. The order in which this happened was different
3
between all combinations of drain/drain_all and begin/end.
4
5
The correct order is to keep children only drained when their parents
6
are also drained. This means that at the start of a drained section, the
7
AioContext needs to be drained first, the parents second and only then
8
the children. The correct order for the end of a drained section is the
9
opposite.
10
11
This patch changes the three other functions to follow the example of
12
bdrv_drained_begin(), which is the only one that got it right.
3
13
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Jeff Cody <jcody@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
16
---
8
tests/qemu-iotests/iotests.py | 11 +++++++++++
17
block/io.c | 12 ++++++++----
9
1 file changed, 11 insertions(+)
18
1 file changed, 8 insertions(+), 4 deletions(-)
10
19
11
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
20
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/iotests.py
22
--- a/block/io.c
14
+++ b/tests/qemu-iotests/iotests.py
23
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ def filter_qmp_event(event):
24
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
16
event['timestamp']['microseconds'] = 'USECS'
25
return;
17
return event
26
}
18
27
19
+def filter_testfiles(msg):
28
+ /* Stop things in parent-to-child order */
20
+ prefix = os.path.join(test_dir, "%s-" % (os.getpid()))
29
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
21
+ return msg.replace(prefix, 'TEST_DIR/PID-')
30
aio_disable_external(bdrv_get_aio_context(bs));
22
+
31
bdrv_parent_drained_begin(bs);
23
def log(msg, filters=[]):
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
24
for flt in filters:
33
return;
25
msg = flt(msg)
34
}
26
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
35
27
result.append(filter_qmp_event(ev))
36
- bdrv_parent_drained_end(bs);
28
return result
37
+ /* Re-enable things in child-to-parent order */
29
38
bdrv_drain_invoke(bs, false);
30
+ def qmp_log(self, cmd, filters=[filter_testfiles], **kwargs):
39
+ bdrv_parent_drained_end(bs);
31
+ logmsg = "{'execute': '%s', 'arguments': %s}" % (cmd, kwargs)
40
aio_enable_external(bdrv_get_aio_context(bs));
32
+ log(logmsg, filters)
41
}
33
+ result = self.qmp(cmd, **kwargs)
42
34
+ log(str(result), filters)
43
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
35
+ return result
44
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
36
+
45
AioContext *aio_context = bdrv_get_aio_context(bs);
37
46
38
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
47
+ /* Stop things in parent-to-child order */
48
aio_context_acquire(aio_context);
49
- bdrv_parent_drained_begin(bs);
50
aio_disable_external(aio_context);
51
+ bdrv_parent_drained_begin(bs);
52
bdrv_drain_invoke(bs, true);
53
aio_context_release(aio_context);
54
55
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
56
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
57
AioContext *aio_context = bdrv_get_aio_context(bs);
58
59
+ /* Re-enable things in child-to-parent order */
60
aio_context_acquire(aio_context);
61
- aio_enable_external(aio_context);
62
- bdrv_parent_drained_end(bs);
63
bdrv_drain_invoke(bs, false);
64
+ bdrv_parent_drained_end(bs);
65
+ aio_enable_external(aio_context);
66
aio_context_release(aio_context);
67
}
39
68
40
--
69
--
41
2.13.6
70
2.13.6
42
71
43
72
diff view generated by jsdifflib
1
.bdrv_co_create() is supposed to return 0 on success, but vdi could
1
Commit 15afd94a047 added code to acquire and release the AioContext in
2
return a positive value instead. Fix this.
2
qemuio_command(). This means that the lock is taken twice now in the
3
call path from hmp_qemu_io(). This causes BDRV_POLL_WHILE() to hang for
4
any requests issued to nodes in a non-mainloop AioContext.
5
6
Dropping the first locking from hmp_qemu_io() fixes the problem.
3
7
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
10
---
8
block/vdi.c | 1 +
11
hmp.c | 6 ------
9
1 file changed, 1 insertion(+)
12
1 file changed, 6 deletions(-)
10
13
11
diff --git a/block/vdi.c b/block/vdi.c
14
diff --git a/hmp.c b/hmp.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/block/vdi.c
16
--- a/hmp.c
14
+++ b/block/vdi.c
17
+++ b/hmp.c
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
18
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
19
{
20
BlockBackend *blk;
21
BlockBackend *local_blk = NULL;
22
- AioContext *aio_context;
23
const char* device = qdict_get_str(qdict, "device");
24
const char* command = qdict_get_str(qdict, "command");
25
Error *err = NULL;
26
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
16
}
27
}
17
}
28
}
18
29
19
+ ret = 0;
30
- aio_context = blk_get_aio_context(blk);
20
exit:
31
- aio_context_acquire(aio_context);
21
blk_unref(blk);
32
-
22
bdrv_unref(bs_file);
33
/*
34
* Notably absent: Proper permission management. This is sad, but it seems
35
* almost impossible to achieve without changing the semantics and thereby
36
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
37
*/
38
qemuio_command(blk, command);
39
40
- aio_context_release(aio_context);
41
-
42
fail:
43
blk_unref(local_blk);
44
hmp_handle_error(mon, &err);
23
--
45
--
24
2.13.6
46
2.13.6
25
47
26
48
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
2
2
3
MIN_REFCOUNT_CACHE_SIZE is 4 and the cluster size is guaranteed to be
3
Since bdrv_co_preadv does all neccessary checks including
4
at most 2MB, so the minimum refcount cache size (in bytes) is always
4
reading after the end of the backing file, avoid duplication
5
going to fit in a 32-bit integer.
5
of verification before bdrv_co_preadv call.
6
6
7
Coverity doesn't know that, and since we're storing the result in a
7
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
8
uint64_t (*refcount_cache_size) it thinks that we need the 64 bits and
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
that we probably want to do a 64-bit multiplication to prevent the
10
result from being truncated.
11
12
This is a false positive in this case, but it's a fair warning.
13
We could do a 64-bit multiplication to get rid of it, but since we
14
know that a 32-bit variable is enough to store this value let's simply
15
reuse min_refcount_cache, make it a normal int and stop doing casts.
16
17
Reported-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Alberto Garcia <berto@igalia.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
11
---
22
block/qcow2.c | 5 ++---
12
block/qcow2.h | 3 ---
23
1 file changed, 2 insertions(+), 3 deletions(-)
13
block/qcow2.c | 51 ++++++++-------------------------------------------
14
2 files changed, 8 insertions(+), 46 deletions(-)
24
15
16
diff --git a/block/qcow2.h b/block/qcow2.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.h
19
+++ b/block/qcow2.h
20
@@ -XXX,XX +XXX,XX @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
21
}
22
23
/* qcow2.c functions */
24
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
25
- int64_t sector_num, int nb_sectors);
26
-
27
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
28
int refcount_order, bool generous_increase,
29
uint64_t *refblock_count);
25
diff --git a/block/qcow2.c b/block/qcow2.c
30
diff --git a/block/qcow2.c b/block/qcow2.c
26
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
27
--- a/block/qcow2.c
32
--- a/block/qcow2.c
28
+++ b/block/qcow2.c
33
+++ b/block/qcow2.c
29
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
34
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
35
return status;
36
}
37
38
-/* handle reading after the end of the backing file */
39
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
40
- int64_t offset, int bytes)
41
-{
42
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
43
- int n1;
44
-
45
- if ((offset + bytes) <= bs_size) {
46
- return bytes;
47
- }
48
-
49
- if (offset >= bs_size) {
50
- n1 = 0;
51
- } else {
52
- n1 = bs_size - offset;
53
- }
54
-
55
- qemu_iovec_memset(qiov, n1, 0, bytes - n1);
56
-
57
- return n1;
58
-}
59
-
60
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
61
uint64_t bytes, QEMUIOVector *qiov,
62
int flags)
63
{
30
BDRVQcow2State *s = bs->opaque;
64
BDRVQcow2State *s = bs->opaque;
31
uint64_t combined_cache_size;
65
- int offset_in_cluster, n1;
32
bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set;
66
+ int offset_in_cluster;
33
+ int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
67
int ret;
34
68
unsigned int cur_bytes; /* number of bytes in current iteration */
35
combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE);
69
uint64_t cluster_offset = 0;
36
l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE);
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
37
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
71
case QCOW2_CLUSTER_UNALLOCATED:
38
} else {
72
39
uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
73
if (bs->backing) {
40
uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);
74
- /* read from the base image */
41
- uint64_t min_refcount_cache =
75
- n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
42
- (uint64_t) MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
76
- offset, cur_bytes);
43
77
- if (n1 > 0) {
44
/* Assign as much memory as possible to the L2 cache, and
78
- QEMUIOVector local_qiov;
45
* use the remainder for the refcount cache */
79
-
46
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
80
- qemu_iovec_init(&local_qiov, hd_qiov.niov);
47
* s->cluster_size);
81
- qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1);
48
}
82
-
49
if (!refcount_cache_size_set) {
83
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
50
- *refcount_cache_size = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
84
- qemu_co_mutex_unlock(&s->lock);
51
+ *refcount_cache_size = min_refcount_cache;
85
- ret = bdrv_co_preadv(bs->backing, offset, n1,
52
}
86
- &local_qiov, 0);
53
}
87
- qemu_co_mutex_lock(&s->lock);
54
88
-
89
- qemu_iovec_destroy(&local_qiov);
90
-
91
- if (ret < 0) {
92
- goto fail;
93
- }
94
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
95
+ qemu_co_mutex_unlock(&s->lock);
96
+ ret = bdrv_co_preadv(bs->backing, offset, cur_bytes,
97
+ &hd_qiov, 0);
98
+ qemu_co_mutex_lock(&s->lock);
99
+ if (ret < 0) {
100
+ goto fail;
101
}
102
} else {
103
/* Note: in this case, no need to wait */
55
--
104
--
56
2.13.6
105
2.13.6
57
106
58
107
diff view generated by jsdifflib
1
We're ready to declare the blockdev-create job stable. This renames the
1
Removing a quorum child node with x-blockdev-change results in a quorum
2
corresponding QMP command from x-blockdev-create to blockdev-create.
2
driver state that cannot be recreated with create options because it
3
would require a list with gaps. This causes trouble in at least
4
.bdrv_refresh_filename().
5
6
Document this problem so that we won't accidentally mark the command
7
stable without having addressed it.
3
8
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
11
---
8
qapi/block-core.json | 4 ++--
12
qapi/block-core.json | 4 ++++
9
qapi/job.json | 2 +-
13
1 file changed, 4 insertions(+)
10
block/create.c | 4 ++--
11
tests/qemu-iotests/206 | 2 +-
12
tests/qemu-iotests/206.out | 54 +++++++++++++++++++++++-----------------------
13
tests/qemu-iotests/207 | 2 +-
14
tests/qemu-iotests/207.out | 18 ++++++++--------
15
tests/qemu-iotests/210 | 2 +-
16
tests/qemu-iotests/210.out | 18 ++++++++--------
17
tests/qemu-iotests/211 | 2 +-
18
tests/qemu-iotests/211.out | 24 ++++++++++-----------
19
tests/qemu-iotests/212 | 2 +-
20
tests/qemu-iotests/212.out | 42 ++++++++++++++++++------------------
21
tests/qemu-iotests/213 | 2 +-
22
tests/qemu-iotests/213.out | 44 ++++++++++++++++++-------------------
23
15 files changed, 111 insertions(+), 111 deletions(-)
24
14
25
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
26
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
27
--- a/qapi/block-core.json
17
--- a/qapi/block-core.json
28
+++ b/qapi/block-core.json
18
+++ b/qapi/block-core.json
29
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
30
} }
20
# does not support all kinds of operations, all kinds of children, nor
31
21
# all block drivers.
32
##
33
-# @x-blockdev-create:
34
+# @blockdev-create:
35
#
22
#
36
# Starts a job to create an image format on a given node. The job is
23
+# FIXME Removing children from a quorum node means introducing gaps in the
37
# automatically finalized, but a manual job-dismiss is required.
24
+# child indices. This cannot be represented in the 'children' list of
38
@@ -XXX,XX +XXX,XX @@
25
+# BlockdevOptionsQuorum, as returned by .bdrv_refresh_filename().
26
+#
27
# Warning: The data in a new quorum child MUST be consistent with that of
28
# the rest of the array.
39
#
29
#
40
# Since: 3.0
41
##
42
-{ 'command': 'x-blockdev-create',
43
+{ 'command': 'blockdev-create',
44
'data': { 'job-id': 'str',
45
'options': 'BlockdevCreateOptions' } }
46
47
diff --git a/qapi/job.json b/qapi/job.json
48
index XXXXXXX..XXXXXXX 100644
49
--- a/qapi/job.json
50
+++ b/qapi/job.json
51
@@ -XXX,XX +XXX,XX @@
52
#
53
# @backup: drive backup job type, see "drive-backup"
54
#
55
-# @create: image creation job type, see "x-blockdev-create" (since 3.0)
56
+# @create: image creation job type, see "blockdev-create" (since 3.0)
57
#
58
# Since: 1.7
59
##
60
diff --git a/block/create.c b/block/create.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/create.c
63
+++ b/block/create.c
64
@@ -XXX,XX +XXX,XX @@ static const JobDriver blockdev_create_job_driver = {
65
.start = blockdev_create_run,
66
};
67
68
-void qmp_x_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
69
- Error **errp)
70
+void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
71
+ Error **errp)
72
{
73
BlockdevCreateJob *s;
74
const char *fmt = BlockdevDriver_str(options->driver);
75
diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
76
index XXXXXXX..XXXXXXX 100755
77
--- a/tests/qemu-iotests/206
78
+++ b/tests/qemu-iotests/206
79
@@ -XXX,XX +XXX,XX @@ from iotests import imgfmt
80
iotests.verify_image_format(supported_fmts=['qcow2'])
81
82
def blockdev_create(vm, options):
83
- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
84
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
85
86
if 'return' in result:
87
assert result['return'] == {}
88
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
89
index XXXXXXX..XXXXXXX 100644
90
--- a/tests/qemu-iotests/206.out
91
+++ b/tests/qemu-iotests/206.out
92
@@ -XXX,XX +XXX,XX @@
93
=== Successful image creation (defaults) ===
94
95
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
96
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
97
{u'return': {}}
98
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
99
{u'return': {}}
100
101
{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}
102
{u'return': {}}
103
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'imgfile', 'size': 134217728}}}
104
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'imgfile', 'size': 134217728}}}
105
{u'return': {}}
106
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
107
{u'return': {}}
108
@@ -XXX,XX +XXX,XX @@ Format specific information:
109
110
=== Successful image creation (inline blockdev-add, explicit defaults) ===
111
112
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': False, 'preallocation': 'off', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
113
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': False, 'preallocation': 'off', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
114
{u'return': {}}
115
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
116
{u'return': {}}
117
118
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'refcount-bits': 16, 'version': 'v3', 'preallocation': 'off', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': False, 'driver': 'qcow2', 'size': 67108864}}}
119
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'refcount-bits': 16, 'version': 'v3', 'preallocation': 'off', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': False, 'driver': 'qcow2', 'size': 67108864}}}
120
{u'return': {}}
121
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
122
{u'return': {}}
123
@@ -XXX,XX +XXX,XX @@ Format specific information:
124
125
=== Successful image creation (v3 non-default options) ===
126
127
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': True, 'preallocation': 'falloc', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
128
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': True, 'preallocation': 'falloc', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
129
{u'return': {}}
130
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
131
{u'return': {}}
132
133
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 2097152, 'refcount-bits': 1, 'version': 'v3', 'preallocation': 'metadata', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': True, 'driver': 'qcow2', 'size': 33554432}}}
134
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 2097152, 'refcount-bits': 1, 'version': 'v3', 'preallocation': 'metadata', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': True, 'driver': 'qcow2', 'size': 33554432}}}
135
{u'return': {}}
136
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
137
{u'return': {}}
138
@@ -XXX,XX +XXX,XX @@ Format specific information:
139
140
=== Successful image creation (v2 non-default options) ===
141
142
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
143
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
144
{u'return': {}}
145
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
146
{u'return': {}}
147
148
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'backing-fmt': 'qcow2', 'driver': 'qcow2', 'version': 'v2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'backing-file': 'TEST_DIR/PID-t.qcow2.base', 'size': 33554432}}}
149
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'backing-fmt': 'qcow2', 'driver': 'qcow2', 'version': 'v2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'backing-file': 'TEST_DIR/PID-t.qcow2.base', 'size': 33554432}}}
150
{u'return': {}}
151
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
152
{u'return': {}}
153
@@ -XXX,XX +XXX,XX @@ Format specific information:
154
155
=== Successful image creation (encrypted) ===
156
157
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'encrypt': {'key-secret': 'keysec0', 'iter-time': 10, 'cipher-mode': 'ctr', 'ivgen-hash-alg': 'md5', 'cipher-alg': 'twofish-128', 'format': 'luks', 'ivgen-alg': 'plain64', 'hash-alg': 'sha1'}, 'driver': 'qcow2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'size': 33554432}}}
158
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'encrypt': {'key-secret': 'keysec0', 'iter-time': 10, 'cipher-mode': 'ctr', 'ivgen-hash-alg': 'md5', 'cipher-alg': 'twofish-128', 'format': 'luks', 'ivgen-alg': 'plain64', 'hash-alg': 'sha1'}, 'driver': 'qcow2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'size': 33554432}}}
159
{u'return': {}}
160
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
161
{u'return': {}}
162
@@ -XXX,XX +XXX,XX @@ Format specific information:
163
164
=== Invalid BlockdevRef ===
165
166
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': "this doesn't exist", 'size': 33554432}}}
167
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': "this doesn't exist", 'size': 33554432}}}
168
{u'return': {}}
169
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
170
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
171
{u'return': {}}
172
173
=== Invalid sizes ===
174
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 1234}}}
175
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 1234}}}
176
{u'return': {}}
177
Job failed: Image size must be a multiple of 512 bytes
178
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
179
{u'return': {}}
180
181
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 18446744073709551104L}}}
182
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 18446744073709551104L}}}
183
{u'return': {}}
184
Job failed: Could not resize image: Image size cannot be negative
185
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
186
{u'return': {}}
187
188
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775808L}}}
189
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775808L}}}
190
{u'return': {}}
191
Job failed: Could not resize image: Image size cannot be negative
192
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
193
{u'return': {}}
194
195
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775296}}}
196
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775296}}}
197
{u'return': {}}
198
Job failed: Could not resize image: Failed to grow the L1 table: File too large
199
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
200
{u'return': {}}
201
202
=== Invalid version ===
203
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'version': 'v1', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
204
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'version': 'v1', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
205
{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter 'v1'"}}
206
207
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'lazy-refcounts': True, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
208
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'lazy-refcounts': True, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
209
{u'return': {}}
210
Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
211
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
212
{u'return': {}}
213
214
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 8, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
215
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 8, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
216
{u'return': {}}
217
Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
218
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
219
{u'return': {}}
220
221
=== Invalid backing file options ===
222
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'full', 'driver': 'qcow2', 'backing-file': '/dev/null', 'file': 'node0', 'size': 67108864}}}
223
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'full', 'driver': 'qcow2', 'backing-file': '/dev/null', 'file': 'node0', 'size': 67108864}}}
224
{u'return': {}}
225
Job failed: Backing file and preallocation cannot be used at the same time
226
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
227
{u'return': {}}
228
229
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'backing-fmt': 'qcow2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
230
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'backing-fmt': 'qcow2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
231
{u'return': {}}
232
Job failed: Backing format cannot be used without backing file
233
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
234
{u'return': {}}
235
236
=== Invalid cluster size ===
237
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
238
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
239
{u'return': {}}
240
Job failed: Cluster size must be a power of two between 512 and 2048k
241
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
242
{u'return': {}}
243
244
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
245
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
246
{u'return': {}}
247
Job failed: Cluster size must be a power of two between 512 and 2048k
248
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
249
{u'return': {}}
250
251
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4194304, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
252
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4194304, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
253
{u'return': {}}
254
Job failed: Cluster size must be a power of two between 512 and 2048k
255
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
256
{u'return': {}}
257
258
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
259
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
260
{u'return': {}}
261
Job failed: Cluster size must be a power of two between 512 and 2048k
262
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
263
{u'return': {}}
264
265
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'qcow2', 'file': 'node0', 'size': 281474976710656}}}
266
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'qcow2', 'file': 'node0', 'size': 281474976710656}}}
267
{u'return': {}}
268
Job failed: Could not resize image: Failed to grow the L1 table: File too large
269
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
270
{u'return': {}}
271
272
=== Invalid refcount width ===
273
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
274
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
275
{u'return': {}}
276
Job failed: Refcount width must be a power of two and may not exceed 64 bits
277
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
278
{u'return': {}}
279
280
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
281
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
282
{u'return': {}}
283
Job failed: Refcount width must be a power of two and may not exceed 64 bits
284
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
285
{u'return': {}}
286
287
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 7, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
288
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 7, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
289
{u'return': {}}
290
Job failed: Refcount width must be a power of two and may not exceed 64 bits
291
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
292
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
293
index XXXXXXX..XXXXXXX 100755
294
--- a/tests/qemu-iotests/207
295
+++ b/tests/qemu-iotests/207
296
@@ -XXX,XX +XXX,XX @@ def filter_hash(msg):
297
return re.sub("'hash': '[0-9a-f]+'", "'hash': HASH", msg)
298
299
def blockdev_create(vm, options):
300
- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options,
301
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
302
filters=[iotests.filter_testfiles, filter_hash])
303
304
if 'return' in result:
305
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
306
index XXXXXXX..XXXXXXX 100644
307
--- a/tests/qemu-iotests/207.out
308
+++ b/tests/qemu-iotests/207.out
309
@@ -XXX,XX +XXX,XX @@
310
=== Successful image creation (defaults) ===
311
312
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
313
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
314
{u'return': {}}
315
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
316
{u'return': {}}
317
@@ -XXX,XX +XXX,XX @@ virtual size: 4.0M (4194304 bytes)
318
319
=== Test host-key-check options ===
320
321
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}}
322
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}}
323
{u'return': {}}
324
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
325
{u'return': {}}
326
@@ -XXX,XX +XXX,XX @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
327
file format: IMGFMT
328
virtual size: 8.0M (8388608 bytes)
329
330
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'known_hosts'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
331
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'known_hosts'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
332
{u'return': {}}
333
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
334
{u'return': {}}
335
@@ -XXX,XX +XXX,XX @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
336
file format: IMGFMT
337
virtual size: 4.0M (4194304 bytes)
338
339
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}}
340
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}}
341
{u'return': {}}
342
Job failed: remote host key does not match host_key_check 'wrong'
343
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
344
{u'return': {}}
345
346
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}}
347
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}}
348
{u'return': {}}
349
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
350
{u'return': {}}
351
@@ -XXX,XX +XXX,XX @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
352
file format: IMGFMT
353
virtual size: 8.0M (8388608 bytes)
354
355
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}}
356
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}}
357
{u'return': {}}
358
Job failed: remote host key does not match host_key_check 'wrong'
359
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
360
{u'return': {}}
361
362
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
363
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
364
{u'return': {}}
365
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
366
{u'return': {}}
367
@@ -XXX,XX +XXX,XX @@ virtual size: 4.0M (4194304 bytes)
368
369
=== Invalid path and user ===
370
371
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': '/this/is/not/an/existing/path', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
372
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': '/this/is/not/an/existing/path', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
373
{u'return': {}}
374
Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)
375
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
376
{u'return': {}}
377
378
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'user': 'invalid user', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
379
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'user': 'invalid user', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
380
{u'return': {}}
381
Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent
382
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
383
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
384
index XXXXXXX..XXXXXXX 100755
385
--- a/tests/qemu-iotests/210
386
+++ b/tests/qemu-iotests/210
387
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['luks'])
388
iotests.verify_protocol(supported=['file'])
389
390
def blockdev_create(vm, options):
391
- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
392
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
393
394
if 'return' in result:
395
assert result['return'] == {}
396
diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out
397
index XXXXXXX..XXXXXXX 100644
398
--- a/tests/qemu-iotests/210.out
399
+++ b/tests/qemu-iotests/210.out
400
@@ -XXX,XX +XXX,XX @@
401
=== Successful image creation (defaults) ===
402
403
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}}
404
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}}
405
{u'return': {}}
406
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
407
{u'return': {}}
408
409
{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}
410
{u'return': {}}
411
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'imgfile', 'size': 134217728}}}
412
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'imgfile', 'size': 134217728}}}
413
{u'return': {}}
414
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
415
{u'return': {}}
416
@@ -XXX,XX +XXX,XX @@ Format specific information:
417
418
=== Successful image creation (with non-default options) ===
419
420
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}}
421
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}}
422
{u'return': {}}
423
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
424
{u'return': {}}
425
426
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'hash-alg': 'sha1', 'cipher-mode': 'ctr', 'cipher-alg': 'twofish-128', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}, 'iter-time': 10, 'ivgen-alg': 'plain64', 'ivgen-hash-alg': 'md5', 'driver': 'luks', 'size': 67108864}}}
427
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'hash-alg': 'sha1', 'cipher-mode': 'ctr', 'cipher-alg': 'twofish-128', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}, 'iter-time': 10, 'ivgen-alg': 'plain64', 'ivgen-hash-alg': 'md5', 'driver': 'luks', 'size': 67108864}}}
428
{u'return': {}}
429
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
430
{u'return': {}}
431
@@ -XXX,XX +XXX,XX @@ Format specific information:
432
433
=== Invalid BlockdevRef ===
434
435
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'luks', 'file': "this doesn't exist", 'size': 67108864}}}
436
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'luks', 'file': "this doesn't exist", 'size': 67108864}}}
437
{u'return': {}}
438
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
439
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
440
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
441
442
=== Zero size ===
443
444
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'node0', 'size': 0}}}
445
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'node0', 'size': 0}}}
446
{u'return': {}}
447
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
448
{u'return': {}}
449
@@ -XXX,XX +XXX,XX @@ Format specific information:
450
451
=== Invalid sizes ===
452
453
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 18446744073709551104L}}}
454
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 18446744073709551104L}}}
455
{u'return': {}}
456
Job failed: The requested file size is too large
457
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
458
{u'return': {}}
459
460
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775808L}}}
461
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775808L}}}
462
{u'return': {}}
463
Job failed: The requested file size is too large
464
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
465
{u'return': {}}
466
467
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775296}}}
468
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775296}}}
469
{u'return': {}}
470
Job failed: The requested file size is too large
471
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
472
diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211
473
index XXXXXXX..XXXXXXX 100755
474
--- a/tests/qemu-iotests/211
475
+++ b/tests/qemu-iotests/211
476
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['vdi'])
477
iotests.verify_protocol(supported=['file'])
478
479
def blockdev_create(vm, options):
480
- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
481
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
482
483
if 'return' in result:
484
assert result['return'] == {}
485
diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out
486
index XXXXXXX..XXXXXXX 100644
487
--- a/tests/qemu-iotests/211.out
488
+++ b/tests/qemu-iotests/211.out
489
@@ -XXX,XX +XXX,XX @@
490
=== Successful image creation (defaults) ===
491
492
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
493
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
494
{u'return': {}}
495
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
496
{u'return': {}}
497
498
{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}
499
{u'return': {}}
500
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'imgfile', 'size': 134217728}}}
501
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'imgfile', 'size': 134217728}}}
502
{u'return': {}}
503
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
504
{u'return': {}}
505
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
506
507
=== Successful image creation (explicit defaults) ===
508
509
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
510
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
511
{u'return': {}}
512
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
513
{u'return': {}}
514
515
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'off', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 67108864}}}
516
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'off', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 67108864}}}
517
{u'return': {}}
518
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
519
{u'return': {}}
520
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
521
522
=== Successful image creation (with non-default options) ===
523
524
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
525
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
526
{u'return': {}}
527
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
528
{u'return': {}}
529
530
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'metadata', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 33554432}}}
531
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'metadata', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 33554432}}}
532
{u'return': {}}
533
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
534
{u'return': {}}
535
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
536
537
=== Invalid BlockdevRef ===
538
539
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': "this doesn't exist", 'size': 33554432}}}
540
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': "this doesn't exist", 'size': 33554432}}}
541
{u'return': {}}
542
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
543
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
544
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
545
546
=== Zero size ===
547
548
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 0}}}
549
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 0}}}
550
{u'return': {}}
551
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
552
{u'return': {}}
553
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
554
555
=== Maximum size ===
556
557
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203584}}}
558
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203584}}}
559
{u'return': {}}
560
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
561
{u'return': {}}
562
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
563
564
=== Invalid sizes ===
565
566
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 18446744073709551104L}}}
567
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 18446744073709551104L}}}
568
{u'return': {}}
569
Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)
570
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
571
{u'return': {}}
572
573
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 9223372036854775808L}}}
574
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 9223372036854775808L}}}
575
{u'return': {}}
576
Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)
577
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
578
{u'return': {}}
579
580
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203585}}}
581
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203585}}}
582
{u'return': {}}
583
Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)
584
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
585
diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212
586
index XXXXXXX..XXXXXXX 100755
587
--- a/tests/qemu-iotests/212
588
+++ b/tests/qemu-iotests/212
589
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['parallels'])
590
iotests.verify_protocol(supported=['file'])
591
592
def blockdev_create(vm, options):
593
- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
594
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
595
596
if 'return' in result:
597
assert result['return'] == {}
598
diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out
599
index XXXXXXX..XXXXXXX 100644
600
--- a/tests/qemu-iotests/212.out
601
+++ b/tests/qemu-iotests/212.out
602
@@ -XXX,XX +XXX,XX @@
603
=== Successful image creation (defaults) ===
604
605
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
606
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
607
{u'return': {}}
608
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
609
{u'return': {}}
610
611
{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}
612
{u'return': {}}
613
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'imgfile', 'size': 134217728}}}
614
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'imgfile', 'size': 134217728}}}
615
{u'return': {}}
616
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
617
{u'return': {}}
618
@@ -XXX,XX +XXX,XX @@ virtual size: 128M (134217728 bytes)
619
620
=== Successful image creation (explicit defaults) ===
621
622
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
623
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
624
{u'return': {}}
625
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
626
{u'return': {}}
627
628
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1048576, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 67108864}}}
629
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1048576, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 67108864}}}
630
{u'return': {}}
631
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
632
{u'return': {}}
633
@@ -XXX,XX +XXX,XX @@ virtual size: 64M (67108864 bytes)
634
635
=== Successful image creation (with non-default options) ===
636
637
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
638
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
639
{u'return': {}}
640
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
641
{u'return': {}}
642
643
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 33554432}}}
644
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 33554432}}}
645
{u'return': {}}
646
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
647
{u'return': {}}
648
@@ -XXX,XX +XXX,XX @@ virtual size: 32M (33554432 bytes)
649
650
=== Invalid BlockdevRef ===
651
652
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': "this doesn't exist", 'size': 33554432}}}
653
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': "this doesn't exist", 'size': 33554432}}}
654
{u'return': {}}
655
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
656
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
657
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
658
659
=== Zero size ===
660
661
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 0}}}
662
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 0}}}
663
{u'return': {}}
664
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
665
{u'return': {}}
666
@@ -XXX,XX +XXX,XX @@ virtual size: 0 (0 bytes)
667
668
=== Maximum size ===
669
670
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627369984}}}
671
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627369984}}}
672
{u'return': {}}
673
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
674
{u'return': {}}
675
@@ -XXX,XX +XXX,XX @@ virtual size: 4096T (4503599627369984 bytes)
676
677
=== Invalid sizes ===
678
679
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 1234}}}
680
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 1234}}}
681
{u'return': {}}
682
Job failed: Image size must be a multiple of 512 bytes
683
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
684
{u'return': {}}
685
686
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 18446744073709551104L}}}
687
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 18446744073709551104L}}}
688
{u'return': {}}
689
Job failed: Image size is too large for this cluster size
690
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
691
{u'return': {}}
692
693
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775808L}}}
694
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775808L}}}
695
{u'return': {}}
696
Job failed: Image size is too large for this cluster size
697
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
698
{u'return': {}}
699
700
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775296}}}
701
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775296}}}
702
{u'return': {}}
703
Job failed: Image size is too large for this cluster size
704
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
705
{u'return': {}}
706
707
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627370497}}}
708
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627370497}}}
709
{u'return': {}}
710
Job failed: Image size is too large for this cluster size
711
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
712
@@ -XXX,XX +XXX,XX @@ Job failed: Image size is too large for this cluster size
713
714
=== Invalid cluster size ===
715
716
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
717
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
718
{u'return': {}}
719
Job failed: Cluster size must be a multiple of 512 bytes
720
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
721
{u'return': {}}
722
723
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
724
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
725
{u'return': {}}
726
Job failed: Cluster size must be a multiple of 512 bytes
727
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
728
{u'return': {}}
729
730
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4294967296, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
731
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4294967296, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
732
{u'return': {}}
733
Job failed: Cluster size is too large
734
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
735
{u'return': {}}
736
737
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 9223372036854775808L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
738
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 9223372036854775808L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
739
{u'return': {}}
740
Job failed: Cluster size is too large
741
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
742
{u'return': {}}
743
744
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 18446744073709551104L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
745
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 18446744073709551104L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
746
{u'return': {}}
747
Job failed: Cluster size is too large
748
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
749
{u'return': {}}
750
751
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
752
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
753
{u'return': {}}
754
Job failed: Image size is too large for this cluster size
755
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
756
{u'return': {}}
757
758
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'parallels', 'file': 'node0', 'size': 281474976710656}}}
759
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'parallels', 'file': 'node0', 'size': 281474976710656}}}
760
{u'return': {}}
761
Job failed: Image size is too large for this cluster size
762
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
763
diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213
764
index XXXXXXX..XXXXXXX 100755
765
--- a/tests/qemu-iotests/213
766
+++ b/tests/qemu-iotests/213
767
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['vhdx'])
768
iotests.verify_protocol(supported=['file'])
769
770
def blockdev_create(vm, options):
771
- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
772
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
773
774
if 'return' in result:
775
assert result['return'] == {}
776
diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out
777
index XXXXXXX..XXXXXXX 100644
778
--- a/tests/qemu-iotests/213.out
779
+++ b/tests/qemu-iotests/213.out
780
@@ -XXX,XX +XXX,XX @@
781
=== Successful image creation (defaults) ===
782
783
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
784
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
785
{u'return': {}}
786
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
787
{u'return': {}}
788
789
{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}
790
{u'return': {}}
791
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'imgfile', 'size': 134217728}}}
792
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'imgfile', 'size': 134217728}}}
793
{u'return': {}}
794
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
795
{u'return': {}}
796
@@ -XXX,XX +XXX,XX @@ cluster_size: 8388608
797
798
=== Successful image creation (explicit defaults) ===
799
800
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
801
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
802
{u'return': {}}
803
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
804
{u'return': {}}
805
806
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 8388608, 'driver': 'vhdx', 'subformat': 'dynamic', 'log-size': 1048576, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': True, 'size': 67108864}}}
807
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 8388608, 'driver': 'vhdx', 'subformat': 'dynamic', 'log-size': 1048576, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': True, 'size': 67108864}}}
808
{u'return': {}}
809
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
810
{u'return': {}}
811
@@ -XXX,XX +XXX,XX @@ cluster_size: 8388608
812
813
=== Successful image creation (with non-default options) ===
814
815
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
816
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
817
{u'return': {}}
818
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
819
{u'return': {}}
820
821
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 268435456, 'driver': 'vhdx', 'subformat': 'fixed', 'log-size': 8388608, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': False, 'size': 33554432}}}
822
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 268435456, 'driver': 'vhdx', 'subformat': 'fixed', 'log-size': 8388608, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': False, 'size': 33554432}}}
823
{u'return': {}}
824
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
825
{u'return': {}}
826
@@ -XXX,XX +XXX,XX @@ cluster_size: 268435456
827
828
=== Invalid BlockdevRef ===
829
830
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': "this doesn't exist", 'size': 33554432}}}
831
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': "this doesn't exist", 'size': 33554432}}}
832
{u'return': {}}
833
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
834
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
835
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
836
837
=== Zero size ===
838
839
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 0}}}
840
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 0}}}
841
{u'return': {}}
842
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
843
{u'return': {}}
844
@@ -XXX,XX +XXX,XX @@ cluster_size: 8388608
845
846
=== Maximum size ===
847
848
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177664}}}
849
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177664}}}
850
{u'return': {}}
851
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
852
{u'return': {}}
853
@@ -XXX,XX +XXX,XX @@ cluster_size: 67108864
854
855
=== Invalid sizes ===
856
857
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 18446744073709551104L}}}
858
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 18446744073709551104L}}}
859
{u'return': {}}
860
Job failed: Image size too large; max of 64TB
861
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
862
{u'return': {}}
863
864
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775808L}}}
865
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775808L}}}
866
{u'return': {}}
867
Job failed: Image size too large; max of 64TB
868
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
869
{u'return': {}}
870
871
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775296}}}
872
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775296}}}
873
{u'return': {}}
874
Job failed: Image size too large; max of 64TB
875
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
876
{u'return': {}}
877
878
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177665}}}
879
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177665}}}
880
{u'return': {}}
881
Job failed: Image size too large; max of 64TB
882
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
883
@@ -XXX,XX +XXX,XX @@ Job failed: Image size too large; max of 64TB
884
885
=== Invalid block size ===
886
887
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 1234567, 'file': 'node0', 'size': 67108864}}}
888
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 1234567, 'file': 'node0', 'size': 67108864}}}
889
{u'return': {}}
890
Job failed: Block size must be a multiple of 1 MB
891
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
892
{u'return': {}}
893
894
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 128, 'file': 'node0', 'size': 67108864}}}
895
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 128, 'file': 'node0', 'size': 67108864}}}
896
{u'return': {}}
897
Job failed: Block size must be a multiple of 1 MB
898
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
899
{u'return': {}}
900
901
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 3145728, 'file': 'node0', 'size': 67108864}}}
902
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 3145728, 'file': 'node0', 'size': 67108864}}}
903
{u'return': {}}
904
Job failed: Block size must be a power of two
905
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
906
{u'return': {}}
907
908
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 536870912, 'file': 'node0', 'size': 67108864}}}
909
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 536870912, 'file': 'node0', 'size': 67108864}}}
910
{u'return': {}}
911
Job failed: Block size must not exceed 268435456
912
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
913
{u'return': {}}
914
915
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 0, 'file': 'node0', 'size': 67108864}}}
916
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 0, 'file': 'node0', 'size': 67108864}}}
917
{u'return': {}}
918
Job failed: Block size must be a multiple of 1 MB
919
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
920
@@ -XXX,XX +XXX,XX @@ Job failed: Block size must be a multiple of 1 MB
921
922
=== Invalid log size ===
923
924
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 1234567, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
925
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 1234567, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
926
{u'return': {}}
927
Job failed: Log size must be a multiple of 1 MB
928
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
929
{u'return': {}}
930
931
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 128, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
932
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 128, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
933
{u'return': {}}
934
Job failed: Log size must be a multiple of 1 MB
935
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
936
{u'return': {}}
937
938
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 4294967296, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
939
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 4294967296, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
940
{u'return': {}}
941
Job failed: Log size must be smaller than 4 GB
942
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
943
{u'return': {}}
944
945
-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 0, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
946
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 0, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
947
{u'return': {}}
948
Job failed: Log size must be a multiple of 1 MB
949
{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
950
--
30
--
951
2.13.6
31
2.13.6
952
32
953
33
diff view generated by jsdifflib
New patch
1
From: Doug Gale <doug16k@gmail.com>
1
2
3
Add trace output for commands, errors, and undefined behavior.
4
Add guest error log output for undefined behavior.
5
Report invalid undefined accesses to MMIO.
6
Annotate unlikely error checks with unlikely.
7
8
Signed-off-by: Doug Gale <doug16k@gmail.com>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
hw/block/nvme.c | 349 ++++++++++++++++++++++++++++++++++++++++++--------
14
hw/block/trace-events | 93 ++++++++++++++
15
2 files changed, 390 insertions(+), 52 deletions(-)
16
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/block/nvme.c
20
+++ b/hw/block/nvme.c
21
@@ -XXX,XX +XXX,XX @@
22
#include "qapi/visitor.h"
23
#include "sysemu/block-backend.h"
24
25
+#include "qemu/log.h"
26
+#include "trace.h"
27
#include "nvme.h"
28
29
+#define NVME_GUEST_ERR(trace, fmt, ...) \
30
+ do { \
31
+ (trace_##trace)(__VA_ARGS__); \
32
+ qemu_log_mask(LOG_GUEST_ERROR, #trace \
33
+ " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
34
+ } while (0)
35
+
36
static void nvme_process_sq(void *opaque);
37
38
static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
39
@@ -XXX,XX +XXX,XX @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
40
{
41
if (cq->irq_enabled) {
42
if (msix_enabled(&(n->parent_obj))) {
43
+ trace_nvme_irq_msix(cq->vector);
44
msix_notify(&(n->parent_obj), cq->vector);
45
} else {
46
+ trace_nvme_irq_pin();
47
pci_irq_pulse(&n->parent_obj);
48
}
49
+ } else {
50
+ trace_nvme_irq_masked();
51
}
52
}
53
54
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
55
trans_len = MIN(len, trans_len);
56
int num_prps = (len >> n->page_bits) + 1;
57
58
- if (!prp1) {
59
+ if (unlikely(!prp1)) {
60
+ trace_nvme_err_invalid_prp();
61
return NVME_INVALID_FIELD | NVME_DNR;
62
} else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
63
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
64
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
65
}
66
len -= trans_len;
67
if (len) {
68
- if (!prp2) {
69
+ if (unlikely(!prp2)) {
70
+ trace_nvme_err_invalid_prp2_missing();
71
goto unmap;
72
}
73
if (len > n->page_size) {
74
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
75
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
76
77
if (i == n->max_prp_ents - 1 && len > n->page_size) {
78
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
79
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
80
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
81
goto unmap;
82
}
83
84
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
85
prp_ent = le64_to_cpu(prp_list[i]);
86
}
87
88
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
89
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
90
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
91
goto unmap;
92
}
93
94
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
95
i++;
96
}
97
} else {
98
- if (prp2 & (n->page_size - 1)) {
99
+ if (unlikely(prp2 & (n->page_size - 1))) {
100
+ trace_nvme_err_invalid_prp2_align(prp2);
101
goto unmap;
102
}
103
if (qsg->nsg) {
104
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
105
QEMUIOVector iov;
106
uint16_t status = NVME_SUCCESS;
107
108
+ trace_nvme_dma_read(prp1, prp2);
109
+
110
if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
111
return NVME_INVALID_FIELD | NVME_DNR;
112
}
113
if (qsg.nsg > 0) {
114
- if (dma_buf_read(ptr, len, &qsg)) {
115
+ if (unlikely(dma_buf_read(ptr, len, &qsg))) {
116
+ trace_nvme_err_invalid_dma();
117
status = NVME_INVALID_FIELD | NVME_DNR;
118
}
119
qemu_sglist_destroy(&qsg);
120
} else {
121
- if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
122
+ if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
123
+ trace_nvme_err_invalid_dma();
124
status = NVME_INVALID_FIELD | NVME_DNR;
125
}
126
qemu_iovec_destroy(&iov);
127
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
128
uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
129
uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
130
131
- if (slba + nlb > ns->id_ns.nsze) {
132
+ if (unlikely(slba + nlb > ns->id_ns.nsze)) {
133
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
134
return NVME_LBA_RANGE | NVME_DNR;
135
}
136
137
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
138
int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
139
enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;
140
141
- if ((slba + nlb) > ns->id_ns.nsze) {
142
+ trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba);
143
+
144
+ if (unlikely((slba + nlb) > ns->id_ns.nsze)) {
145
block_acct_invalid(blk_get_stats(n->conf.blk), acct);
146
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
147
return NVME_LBA_RANGE | NVME_DNR;
148
}
149
150
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
151
NvmeNamespace *ns;
152
uint32_t nsid = le32_to_cpu(cmd->nsid);
153
154
- if (nsid == 0 || nsid > n->num_namespaces) {
155
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
156
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
157
return NVME_INVALID_NSID | NVME_DNR;
158
}
159
160
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
161
case NVME_CMD_READ:
162
return nvme_rw(n, ns, cmd, req);
163
default:
164
+ trace_nvme_err_invalid_opc(cmd->opcode);
165
return NVME_INVALID_OPCODE | NVME_DNR;
166
}
167
}
168
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
169
NvmeCQueue *cq;
170
uint16_t qid = le16_to_cpu(c->qid);
171
172
- if (!qid || nvme_check_sqid(n, qid)) {
173
+ if (unlikely(!qid || nvme_check_sqid(n, qid))) {
174
+ trace_nvme_err_invalid_del_sq(qid);
175
return NVME_INVALID_QID | NVME_DNR;
176
}
177
178
+ trace_nvme_del_sq(qid);
179
+
180
sq = n->sq[qid];
181
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
182
req = QTAILQ_FIRST(&sq->out_req_list);
183
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
184
uint16_t qflags = le16_to_cpu(c->sq_flags);
185
uint64_t prp1 = le64_to_cpu(c->prp1);
186
187
- if (!cqid || nvme_check_cqid(n, cqid)) {
188
+ trace_nvme_create_sq(prp1, sqid, cqid, qsize, qflags);
189
+
190
+ if (unlikely(!cqid || nvme_check_cqid(n, cqid))) {
191
+ trace_nvme_err_invalid_create_sq_cqid(cqid);
192
return NVME_INVALID_CQID | NVME_DNR;
193
}
194
- if (!sqid || !nvme_check_sqid(n, sqid)) {
195
+ if (unlikely(!sqid || !nvme_check_sqid(n, sqid))) {
196
+ trace_nvme_err_invalid_create_sq_sqid(sqid);
197
return NVME_INVALID_QID | NVME_DNR;
198
}
199
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
200
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
201
+ trace_nvme_err_invalid_create_sq_size(qsize);
202
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
203
}
204
- if (!prp1 || prp1 & (n->page_size - 1)) {
205
+ if (unlikely(!prp1 || prp1 & (n->page_size - 1))) {
206
+ trace_nvme_err_invalid_create_sq_addr(prp1);
207
return NVME_INVALID_FIELD | NVME_DNR;
208
}
209
- if (!(NVME_SQ_FLAGS_PC(qflags))) {
210
+ if (unlikely(!(NVME_SQ_FLAGS_PC(qflags)))) {
211
+ trace_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags));
212
return NVME_INVALID_FIELD | NVME_DNR;
213
}
214
sq = g_malloc0(sizeof(*sq));
215
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd)
216
NvmeCQueue *cq;
217
uint16_t qid = le16_to_cpu(c->qid);
218
219
- if (!qid || nvme_check_cqid(n, qid)) {
220
+ if (unlikely(!qid || nvme_check_cqid(n, qid))) {
221
+ trace_nvme_err_invalid_del_cq_cqid(qid);
222
return NVME_INVALID_CQID | NVME_DNR;
223
}
224
225
cq = n->cq[qid];
226
- if (!QTAILQ_EMPTY(&cq->sq_list)) {
227
+ if (unlikely(!QTAILQ_EMPTY(&cq->sq_list))) {
228
+ trace_nvme_err_invalid_del_cq_notempty(qid);
229
return NVME_INVALID_QUEUE_DEL;
230
}
231
+ trace_nvme_del_cq(qid);
232
nvme_free_cq(cq, n);
233
return NVME_SUCCESS;
234
}
235
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
236
uint16_t qflags = le16_to_cpu(c->cq_flags);
237
uint64_t prp1 = le64_to_cpu(c->prp1);
238
239
- if (!cqid || !nvme_check_cqid(n, cqid)) {
240
+ trace_nvme_create_cq(prp1, cqid, vector, qsize, qflags,
241
+ NVME_CQ_FLAGS_IEN(qflags) != 0);
242
+
243
+ if (unlikely(!cqid || !nvme_check_cqid(n, cqid))) {
244
+ trace_nvme_err_invalid_create_cq_cqid(cqid);
245
return NVME_INVALID_CQID | NVME_DNR;
246
}
247
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
248
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
249
+ trace_nvme_err_invalid_create_cq_size(qsize);
250
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
251
}
252
- if (!prp1) {
253
+ if (unlikely(!prp1)) {
254
+ trace_nvme_err_invalid_create_cq_addr(prp1);
255
return NVME_INVALID_FIELD | NVME_DNR;
256
}
257
- if (vector > n->num_queues) {
258
+ if (unlikely(vector > n->num_queues)) {
259
+ trace_nvme_err_invalid_create_cq_vector(vector);
260
return NVME_INVALID_IRQ_VECTOR | NVME_DNR;
261
}
262
- if (!(NVME_CQ_FLAGS_PC(qflags))) {
263
+ if (unlikely(!(NVME_CQ_FLAGS_PC(qflags)))) {
264
+ trace_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags));
265
return NVME_INVALID_FIELD | NVME_DNR;
266
}
267
268
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c)
269
uint64_t prp1 = le64_to_cpu(c->prp1);
270
uint64_t prp2 = le64_to_cpu(c->prp2);
271
272
+ trace_nvme_identify_ctrl();
273
+
274
return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl),
275
prp1, prp2);
276
}
277
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c)
278
uint64_t prp1 = le64_to_cpu(c->prp1);
279
uint64_t prp2 = le64_to_cpu(c->prp2);
280
281
- if (nsid == 0 || nsid > n->num_namespaces) {
282
+ trace_nvme_identify_ns(nsid);
283
+
284
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
285
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
286
return NVME_INVALID_NSID | NVME_DNR;
287
}
288
289
ns = &n->namespaces[nsid - 1];
290
+
291
return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns),
292
prp1, prp2);
293
}
294
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
295
uint16_t ret;
296
int i, j = 0;
297
298
+ trace_nvme_identify_nslist(min_nsid);
299
+
300
list = g_malloc0(data_len);
301
for (i = 0; i < n->num_namespaces; i++) {
302
if (i < min_nsid) {
303
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
304
case 0x02:
305
return nvme_identify_nslist(n, c);
306
default:
307
+ trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns));
308
return NVME_INVALID_FIELD | NVME_DNR;
309
}
310
}
311
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
312
switch (dw10) {
313
case NVME_VOLATILE_WRITE_CACHE:
314
result = blk_enable_write_cache(n->conf.blk);
315
+ trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
316
break;
317
case NVME_NUMBER_OF_QUEUES:
318
result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
319
+ trace_nvme_getfeat_numq(result);
320
break;
321
default:
322
+ trace_nvme_err_invalid_getfeat(dw10);
323
return NVME_INVALID_FIELD | NVME_DNR;
324
}
325
326
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
327
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
328
break;
329
case NVME_NUMBER_OF_QUEUES:
330
+ trace_nvme_setfeat_numq((dw11 & 0xFFFF) + 1,
331
+ ((dw11 >> 16) & 0xFFFF) + 1,
332
+ n->num_queues - 1, n->num_queues - 1);
333
req->cqe.result =
334
cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
335
break;
336
default:
337
+ trace_nvme_err_invalid_setfeat(dw10);
338
return NVME_INVALID_FIELD | NVME_DNR;
339
}
340
return NVME_SUCCESS;
341
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
342
case NVME_ADM_CMD_GET_FEATURES:
343
return nvme_get_feature(n, cmd, req);
344
default:
345
+ trace_nvme_err_invalid_admin_opc(cmd->opcode);
346
return NVME_INVALID_OPCODE | NVME_DNR;
347
}
348
}
349
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
350
uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12;
351
uint32_t page_size = 1 << page_bits;
352
353
- if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq ||
354
- n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) ||
355
- NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) ||
356
- NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) ||
357
- NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) ||
358
- NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) ||
359
- NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) ||
360
- NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) ||
361
- !NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) {
362
+ if (unlikely(n->cq[0])) {
363
+ trace_nvme_err_startfail_cq();
364
+ return -1;
365
+ }
366
+ if (unlikely(n->sq[0])) {
367
+ trace_nvme_err_startfail_sq();
368
+ return -1;
369
+ }
370
+ if (unlikely(!n->bar.asq)) {
371
+ trace_nvme_err_startfail_nbarasq();
372
+ return -1;
373
+ }
374
+ if (unlikely(!n->bar.acq)) {
375
+ trace_nvme_err_startfail_nbaracq();
376
+ return -1;
377
+ }
378
+ if (unlikely(n->bar.asq & (page_size - 1))) {
379
+ trace_nvme_err_startfail_asq_misaligned(n->bar.asq);
380
+ return -1;
381
+ }
382
+ if (unlikely(n->bar.acq & (page_size - 1))) {
383
+ trace_nvme_err_startfail_acq_misaligned(n->bar.acq);
384
+ return -1;
385
+ }
386
+ if (unlikely(NVME_CC_MPS(n->bar.cc) <
387
+ NVME_CAP_MPSMIN(n->bar.cap))) {
388
+ trace_nvme_err_startfail_page_too_small(
389
+ NVME_CC_MPS(n->bar.cc),
390
+ NVME_CAP_MPSMIN(n->bar.cap));
391
+ return -1;
392
+ }
393
+ if (unlikely(NVME_CC_MPS(n->bar.cc) >
394
+ NVME_CAP_MPSMAX(n->bar.cap))) {
395
+ trace_nvme_err_startfail_page_too_large(
396
+ NVME_CC_MPS(n->bar.cc),
397
+ NVME_CAP_MPSMAX(n->bar.cap));
398
+ return -1;
399
+ }
400
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) <
401
+ NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) {
402
+ trace_nvme_err_startfail_cqent_too_small(
403
+ NVME_CC_IOCQES(n->bar.cc),
404
+ NVME_CTRL_CQES_MIN(n->bar.cap));
405
+ return -1;
406
+ }
407
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) >
408
+ NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) {
409
+ trace_nvme_err_startfail_cqent_too_large(
410
+ NVME_CC_IOCQES(n->bar.cc),
411
+ NVME_CTRL_CQES_MAX(n->bar.cap));
412
+ return -1;
413
+ }
414
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) <
415
+ NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) {
416
+ trace_nvme_err_startfail_sqent_too_small(
417
+ NVME_CC_IOSQES(n->bar.cc),
418
+ NVME_CTRL_SQES_MIN(n->bar.cap));
419
+ return -1;
420
+ }
421
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) >
422
+ NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) {
423
+ trace_nvme_err_startfail_sqent_too_large(
424
+ NVME_CC_IOSQES(n->bar.cc),
425
+ NVME_CTRL_SQES_MAX(n->bar.cap));
426
+ return -1;
427
+ }
428
+ if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) {
429
+ trace_nvme_err_startfail_asqent_sz_zero();
430
+ return -1;
431
+ }
432
+ if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) {
433
+ trace_nvme_err_startfail_acqent_sz_zero();
434
return -1;
435
}
436
437
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
438
static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
439
unsigned size)
440
{
441
+ if (unlikely(offset & (sizeof(uint32_t) - 1))) {
442
+ NVME_GUEST_ERR(nvme_ub_mmiowr_misaligned32,
443
+ "MMIO write not 32-bit aligned,"
444
+ " offset=0x%"PRIx64"", offset);
445
+ /* should be ignored, fall through for now */
446
+ }
447
+
448
+ if (unlikely(size < sizeof(uint32_t))) {
449
+ NVME_GUEST_ERR(nvme_ub_mmiowr_toosmall,
450
+ "MMIO write smaller than 32-bits,"
451
+ " offset=0x%"PRIx64", size=%u",
452
+ offset, size);
453
+ /* should be ignored, fall through for now */
454
+ }
455
+
456
switch (offset) {
457
- case 0xc:
458
+ case 0xc: /* INTMS */
459
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
460
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
461
+ "undefined access to interrupt mask set"
462
+ " when MSI-X is enabled");
463
+ /* should be ignored, fall through for now */
464
+ }
465
n->bar.intms |= data & 0xffffffff;
466
n->bar.intmc = n->bar.intms;
467
+ trace_nvme_mmio_intm_set(data & 0xffffffff,
468
+ n->bar.intmc);
469
break;
470
- case 0x10:
471
+ case 0x10: /* INTMC */
472
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
473
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
474
+ "undefined access to interrupt mask clr"
475
+ " when MSI-X is enabled");
476
+ /* should be ignored, fall through for now */
477
+ }
478
n->bar.intms &= ~(data & 0xffffffff);
479
n->bar.intmc = n->bar.intms;
480
+ trace_nvme_mmio_intm_clr(data & 0xffffffff,
481
+ n->bar.intmc);
482
break;
483
- case 0x14:
484
+ case 0x14: /* CC */
485
+ trace_nvme_mmio_cfg(data & 0xffffffff);
486
/* Windows first sends data, then sends enable bit */
487
if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) &&
488
!NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc))
489
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
490
491
if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) {
492
n->bar.cc = data;
493
- if (nvme_start_ctrl(n)) {
494
+ if (unlikely(nvme_start_ctrl(n))) {
495
+ trace_nvme_err_startfail();
496
n->bar.csts = NVME_CSTS_FAILED;
497
} else {
498
+ trace_nvme_mmio_start_success();
499
n->bar.csts = NVME_CSTS_READY;
500
}
501
} else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) {
502
+ trace_nvme_mmio_stopped();
503
nvme_clear_ctrl(n);
504
n->bar.csts &= ~NVME_CSTS_READY;
505
}
506
if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) {
507
- nvme_clear_ctrl(n);
508
- n->bar.cc = data;
509
- n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
510
+ trace_nvme_mmio_shutdown_set();
511
+ nvme_clear_ctrl(n);
512
+ n->bar.cc = data;
513
+ n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
514
} else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) {
515
- n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
516
- n->bar.cc = data;
517
+ trace_nvme_mmio_shutdown_cleared();
518
+ n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
519
+ n->bar.cc = data;
520
+ }
521
+ break;
522
+ case 0x1C: /* CSTS */
523
+ if (data & (1 << 4)) {
524
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ssreset_w1c_unsupported,
525
+ "attempted to W1C CSTS.NSSRO"
526
+ " but CAP.NSSRS is zero (not supported)");
527
+ } else if (data != 0) {
528
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ro_csts,
529
+ "attempted to set a read only bit"
530
+ " of controller status");
531
+ }
532
+ break;
533
+ case 0x20: /* NSSR */
534
+ if (data == 0x4E564D65) {
535
+ trace_nvme_ub_mmiowr_ssreset_unsupported();
536
+ } else {
537
+ /* The spec says that writes of other values have no effect */
538
+ return;
539
}
540
break;
541
- case 0x24:
542
+ case 0x24: /* AQA */
543
n->bar.aqa = data & 0xffffffff;
544
+ trace_nvme_mmio_aqattr(data & 0xffffffff);
545
break;
546
- case 0x28:
547
+ case 0x28: /* ASQ */
548
n->bar.asq = data;
549
+ trace_nvme_mmio_asqaddr(data);
550
break;
551
- case 0x2c:
552
+ case 0x2c: /* ASQ hi */
553
n->bar.asq |= data << 32;
554
+ trace_nvme_mmio_asqaddr_hi(data, n->bar.asq);
555
break;
556
- case 0x30:
557
+ case 0x30: /* ACQ */
558
+ trace_nvme_mmio_acqaddr(data);
559
n->bar.acq = data;
560
break;
561
- case 0x34:
562
+ case 0x34: /* ACQ hi */
563
n->bar.acq |= data << 32;
564
+ trace_nvme_mmio_acqaddr_hi(data, n->bar.acq);
565
break;
566
+ case 0x38: /* CMBLOC */
567
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbloc_reserved,
568
+ "invalid write to reserved CMBLOC"
569
+ " when CMBSZ is zero, ignored");
570
+ return;
571
+ case 0x3C: /* CMBSZ */
572
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
573
+ "invalid write to read only CMBSZ, ignored");
574
+ return;
575
default:
576
+ NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
577
+ "invalid MMIO write,"
578
+ " offset=0x%"PRIx64", data=%"PRIx64"",
579
+ offset, data);
580
break;
581
}
582
}
583
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
584
uint8_t *ptr = (uint8_t *)&n->bar;
585
uint64_t val = 0;
586
587
+ if (unlikely(addr & (sizeof(uint32_t) - 1))) {
588
+ NVME_GUEST_ERR(nvme_ub_mmiord_misaligned32,
589
+ "MMIO read not 32-bit aligned,"
590
+ " offset=0x%"PRIx64"", addr);
591
+ /* should RAZ, fall through for now */
592
+ } else if (unlikely(size < sizeof(uint32_t))) {
593
+ NVME_GUEST_ERR(nvme_ub_mmiord_toosmall,
594
+ "MMIO read smaller than 32-bits,"
595
+ " offset=0x%"PRIx64"", addr);
596
+ /* should RAZ, fall through for now */
597
+ }
598
+
599
if (addr < sizeof(n->bar)) {
600
memcpy(&val, ptr + addr, size);
601
+ } else {
602
+ NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
603
+ "MMIO read beyond last register,"
604
+ " offset=0x%"PRIx64", returning 0", addr);
605
}
606
+
607
return val;
608
}
609
610
@@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
611
{
612
uint32_t qid;
613
614
- if (addr & ((1 << 2) - 1)) {
615
+ if (unlikely(addr & ((1 << 2) - 1))) {
616
+ NVME_GUEST_ERR(nvme_ub_db_wr_misaligned,
617
+ "doorbell write not 32-bit aligned,"
618
+ " offset=0x%"PRIx64", ignoring", addr);
619
return;
620
}
621
622
if (((addr - 0x1000) >> 2) & 1) {
623
+ /* Completion queue doorbell write */
624
+
625
uint16_t new_head = val & 0xffff;
626
int start_sqs;
627
NvmeCQueue *cq;
628
629
qid = (addr - (0x1000 + (1 << 2))) >> 3;
630
- if (nvme_check_cqid(n, qid)) {
631
+ if (unlikely(nvme_check_cqid(n, qid))) {
632
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq,
633
+ "completion queue doorbell write"
634
+ " for nonexistent queue,"
635
+ " sqid=%"PRIu32", ignoring", qid);
636
return;
637
}
638
639
cq = n->cq[qid];
640
- if (new_head >= cq->size) {
641
+ if (unlikely(new_head >= cq->size)) {
642
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cqhead,
643
+ "completion queue doorbell write value"
644
+ " beyond queue size, sqid=%"PRIu32","
645
+ " new_head=%"PRIu16", ignoring",
646
+ qid, new_head);
647
return;
648
}
649
650
@@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
651
nvme_isr_notify(n, cq);
652
}
653
} else {
654
+ /* Submission queue doorbell write */
655
+
656
uint16_t new_tail = val & 0xffff;
657
NvmeSQueue *sq;
658
659
qid = (addr - 0x1000) >> 3;
660
- if (nvme_check_sqid(n, qid)) {
661
+ if (unlikely(nvme_check_sqid(n, qid))) {
662
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sq,
663
+ "submission queue doorbell write"
664
+ " for nonexistent queue,"
665
+ " sqid=%"PRIu32", ignoring", qid);
666
return;
667
}
668
669
sq = n->sq[qid];
670
- if (new_tail >= sq->size) {
671
+ if (unlikely(new_tail >= sq->size)) {
672
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sqtail,
673
+ "submission queue doorbell write value"
674
+ " beyond queue size, sqid=%"PRIu32","
675
+ " new_tail=%"PRIu16", ignoring",
676
+ qid, new_tail);
677
return;
678
}
679
680
diff --git a/hw/block/trace-events b/hw/block/trace-events
681
index XXXXXXX..XXXXXXX 100644
682
--- a/hw/block/trace-events
683
+++ b/hw/block/trace-events
684
@@ -XXX,XX +XXX,XX @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6
685
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
686
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
687
688
+# hw/block/nvme.c
689
+# nvme traces for successful events
690
+nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
691
+nvme_irq_pin(void) "pulsing IRQ pin"
692
+nvme_irq_masked(void) "IRQ is masked"
693
+nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
694
+nvme_rw(char const *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
695
+nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
696
+nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
697
+nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
698
+nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16""
699
+nvme_identify_ctrl(void) "identify controller"
700
+nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
701
+nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
702
+nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s"
703
+nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
704
+nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
705
+nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
706
+nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
707
+nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
708
+nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
709
+nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
710
+nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
711
+nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
712
+nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
713
+nvme_mmio_start_success(void) "setting controller enable bit succeeded"
714
+nvme_mmio_stopped(void) "cleared controller enable bit"
715
+nvme_mmio_shutdown_set(void) "shutdown bit set"
716
+nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
717
+
718
+# nvme traces for error conditions
719
+nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
720
+nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
721
+nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
722
+nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
723
+nvme_err_invalid_field(void) "invalid field"
724
+nvme_err_invalid_prp(void) "invalid PRP"
725
+nvme_err_invalid_sgl(void) "invalid SGL"
726
+nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u"
727
+nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
728
+nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
729
+nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
730
+nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
731
+nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
732
+nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
733
+nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
734
+nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
735
+nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
736
+nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
737
+nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
738
+nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
739
+nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
740
+nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
741
+nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
742
+nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
743
+nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
744
+nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
745
+nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
746
+nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
747
+nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
748
+nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
749
+nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null"
750
+nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64""
751
+nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64""
752
+nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u"
753
+nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u"
754
+nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u"
755
+nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u"
756
+nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u"
757
+nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u"
758
+nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
759
+nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
760
+nvme_err_startfail(void) "setting controller enable bit failed"
761
+
762
+# Traces for undefined behavior
763
+nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64""
764
+nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u"
765
+nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled"
766
+nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status"
767
+nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)"
768
+nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
769
+nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
770
+nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
771
+nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
772
+nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
773
+nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
774
+nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0"
775
+nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring"
776
+nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring"
777
+nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring"
778
+nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring"
779
+nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring"
780
+
781
# hw/block/xen_disk.c
782
xen_disk_alloc(char *name) "%s"
783
xen_disk_init(char *name) "%s"
784
--
785
2.13.6
786
787
diff view generated by jsdifflib
New patch
1
From: Fam Zheng <famz@redhat.com>
1
2
3
Management tools create overlays of running guests with qemu-img:
4
5
$ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2
6
7
but this doesn't work anymore due to image locking:
8
9
qemu-img: /overlay/image.qcow2: Failed to get shared "write" lock
10
Is another process using the image?
11
Could not open backing image to determine size.
12
Use the force share option to allow this use case again.
13
14
Cc: qemu-stable@nongnu.org
15
Signed-off-by: Fam Zheng <famz@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
block.c | 3 ++-
20
1 file changed, 2 insertions(+), 1 deletion(-)
21
22
diff --git a/block.c b/block.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block.c
25
+++ b/block.c
26
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
27
back_flags = flags;
28
back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
29
30
+ backing_options = qdict_new();
31
if (backing_fmt) {
32
- backing_options = qdict_new();
33
qdict_put_str(backing_options, "driver", backing_fmt);
34
}
35
+ qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true);
36
37
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
38
&local_err);
39
--
40
2.13.6
41
42
diff view generated by jsdifflib
New patch
1
From: Thomas Huth <thuth@redhat.com>
1
2
3
It's not working anymore since QEMU v1.3.0 - time to remove it now.
4
5
Signed-off-by: Thomas Huth <thuth@redhat.com>
6
Reviewed-by: John Snow <jsnow@redhat.com>
7
Reviewed-by: Markus Armbruster <armbru@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
blockdev.c | 11 -----------
11
qemu-doc.texi | 6 ------
12
2 files changed, 17 deletions(-)
13
14
diff --git a/blockdev.c b/blockdev.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/blockdev.c
17
+++ b/blockdev.c
18
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
19
.type = QEMU_OPT_STRING,
20
.help = "chs translation (auto, lba, none)",
21
},{
22
- .name = "boot",
23
- .type = QEMU_OPT_BOOL,
24
- .help = "(deprecated, ignored)",
25
- },{
26
.name = "addr",
27
.type = QEMU_OPT_STRING,
28
.help = "pci address (virtio only)",
29
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
30
goto fail;
31
}
32
33
- /* Deprecated option boot=[on|off] */
34
- if (qemu_opt_get(legacy_opts, "boot") != NULL) {
35
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
36
- "ignored. Future versions will reject this parameter. Please "
37
- "update your scripts.\n");
38
- }
39
-
40
/* Other deprecated options */
41
if (!qtest_enabled()) {
42
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
43
diff --git a/qemu-doc.texi b/qemu-doc.texi
44
index XXXXXXX..XXXXXXX 100644
45
--- a/qemu-doc.texi
46
+++ b/qemu-doc.texi
47
@@ -XXX,XX +XXX,XX @@ deprecated.
48
49
@section System emulator command line arguments
50
51
-@subsection -drive boot=on|off (since 1.3.0)
52
-
53
-The ``boot=on|off'' option to the ``-drive'' argument is
54
-ignored. Applications should use the ``bootindex=N'' parameter
55
-to set an absolute ordering between devices instead.
56
-
57
@subsection -tdf (since 1.3.0)
58
59
The ``-tdf'' argument is ignored. The behaviour implemented
60
--
61
2.13.6
62
63
diff view generated by jsdifflib
New patch
1
1
From: Thomas Huth <thuth@redhat.com>
2
3
It's been marked as deprecated since QEMU v2.10.0, and so far nobody
4
complained that we should keep it, so let's remove this legacy option
5
now to simplify the code quite a bit.
6
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
vl.c | 86 ++-------------------------------------------------------
13
qemu-doc.texi | 8 ------
14
qemu-options.hx | 19 ++-----------
15
3 files changed, 4 insertions(+), 109 deletions(-)
16
17
diff --git a/vl.c b/vl.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/vl.c
20
+++ b/vl.c
21
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
22
const char *boot_order = NULL;
23
const char *boot_once = NULL;
24
DisplayState *ds;
25
- int cyls, heads, secs, translation;
26
QemuOpts *opts, *machine_opts;
27
- QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL;
28
+ QemuOpts *icount_opts = NULL, *accel_opts = NULL;
29
QemuOptsList *olist;
30
int optind;
31
const char *optarg;
32
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
33
34
cpu_model = NULL;
35
snapshot = 0;
36
- cyls = heads = secs = 0;
37
- translation = BIOS_ATA_TRANSLATION_AUTO;
38
39
nb_nics = 0;
40
41
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
42
if (optind >= argc)
43
break;
44
if (argv[optind][0] != '-') {
45
- hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
46
+ drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
47
} else {
48
const QEMUOption *popt;
49
50
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
51
cpu_model = optarg;
52
break;
53
case QEMU_OPTION_hda:
54
- {
55
- char buf[256];
56
- if (cyls == 0)
57
- snprintf(buf, sizeof(buf), "%s", HD_OPTS);
58
- else
59
- snprintf(buf, sizeof(buf),
60
- "%s,cyls=%d,heads=%d,secs=%d%s",
61
- HD_OPTS , cyls, heads, secs,
62
- translation == BIOS_ATA_TRANSLATION_LBA ?
63
- ",trans=lba" :
64
- translation == BIOS_ATA_TRANSLATION_NONE ?
65
- ",trans=none" : "");
66
- drive_add(IF_DEFAULT, 0, optarg, buf);
67
- break;
68
- }
69
case QEMU_OPTION_hdb:
70
case QEMU_OPTION_hdc:
71
case QEMU_OPTION_hdd:
72
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
73
case QEMU_OPTION_snapshot:
74
snapshot = 1;
75
break;
76
- case QEMU_OPTION_hdachs:
77
- {
78
- const char *p;
79
- p = optarg;
80
- cyls = strtol(p, (char **)&p, 0);
81
- if (cyls < 1 || cyls > 16383)
82
- goto chs_fail;
83
- if (*p != ',')
84
- goto chs_fail;
85
- p++;
86
- heads = strtol(p, (char **)&p, 0);
87
- if (heads < 1 || heads > 16)
88
- goto chs_fail;
89
- if (*p != ',')
90
- goto chs_fail;
91
- p++;
92
- secs = strtol(p, (char **)&p, 0);
93
- if (secs < 1 || secs > 63)
94
- goto chs_fail;
95
- if (*p == ',') {
96
- p++;
97
- if (!strcmp(p, "large")) {
98
- translation = BIOS_ATA_TRANSLATION_LARGE;
99
- } else if (!strcmp(p, "rechs")) {
100
- translation = BIOS_ATA_TRANSLATION_RECHS;
101
- } else if (!strcmp(p, "none")) {
102
- translation = BIOS_ATA_TRANSLATION_NONE;
103
- } else if (!strcmp(p, "lba")) {
104
- translation = BIOS_ATA_TRANSLATION_LBA;
105
- } else if (!strcmp(p, "auto")) {
106
- translation = BIOS_ATA_TRANSLATION_AUTO;
107
- } else {
108
- goto chs_fail;
109
- }
110
- } else if (*p != '\0') {
111
- chs_fail:
112
- error_report("invalid physical CHS format");
113
- exit(1);
114
- }
115
- if (hda_opts != NULL) {
116
- qemu_opt_set_number(hda_opts, "cyls", cyls,
117
- &error_abort);
118
- qemu_opt_set_number(hda_opts, "heads", heads,
119
- &error_abort);
120
- qemu_opt_set_number(hda_opts, "secs", secs,
121
- &error_abort);
122
- if (translation == BIOS_ATA_TRANSLATION_LARGE) {
123
- qemu_opt_set(hda_opts, "trans", "large",
124
- &error_abort);
125
- } else if (translation == BIOS_ATA_TRANSLATION_RECHS) {
126
- qemu_opt_set(hda_opts, "trans", "rechs",
127
- &error_abort);
128
- } else if (translation == BIOS_ATA_TRANSLATION_LBA) {
129
- qemu_opt_set(hda_opts, "trans", "lba",
130
- &error_abort);
131
- } else if (translation == BIOS_ATA_TRANSLATION_NONE) {
132
- qemu_opt_set(hda_opts, "trans", "none",
133
- &error_abort);
134
- }
135
- }
136
- }
137
- error_report("'-hdachs' is deprecated, please use '-device"
138
- " ide-hd,cyls=c,heads=h,secs=s,...' instead");
139
- break;
140
case QEMU_OPTION_numa:
141
opts = qemu_opts_parse_noisily(qemu_find_opts("numa"),
142
optarg, true);
143
diff --git a/qemu-doc.texi b/qemu-doc.texi
144
index XXXXXXX..XXXXXXX 100644
145
--- a/qemu-doc.texi
146
+++ b/qemu-doc.texi
147
@@ -XXX,XX +XXX,XX @@ The ``--net dump'' argument is now replaced with the
148
``-object filter-dump'' argument which works in combination
149
with the modern ``-netdev`` backends instead.
150
151
-@subsection -hdachs (since 2.10.0)
152
-
153
-The ``-hdachs'' argument is now a synonym for setting
154
-the ``cyls'', ``heads'', ``secs'', and ``trans'' properties
155
-on the ``ide-hd'' device using the ``-device'' argument.
156
-The new syntax allows different settings to be provided
157
-per disk.
158
-
159
@subsection -usbdevice (since 2.10.0)
160
161
The ``-usbdevice DEV'' argument is now a synonym for setting
162
diff --git a/qemu-options.hx b/qemu-options.hx
163
index XXXXXXX..XXXXXXX 100644
164
--- a/qemu-options.hx
165
+++ b/qemu-options.hx
166
@@ -XXX,XX +XXX,XX @@ of available connectors of a given interface type.
167
@item media=@var{media}
168
This option defines the type of the media: disk or cdrom.
169
@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
170
-These options have the same definition as they have in @option{-hdachs}.
171
-These parameters are deprecated, use the corresponding parameters
172
+Force disk physical geometry and the optional BIOS translation (trans=none or
173
+lba). These parameters are deprecated, use the corresponding parameters
174
of @code{-device} instead.
175
@item snapshot=@var{snapshot}
176
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
177
@@ -XXX,XX +XXX,XX @@ the raw disk image you use is not written back. You can however force
178
the write back by pressing @key{C-a s} (@pxref{disk_images}).
179
ETEXI
180
181
-DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
182
- "-hdachs c,h,s[,t]\n" \
183
- " force hard disk 0 physical geometry and the optional BIOS\n" \
184
- " translation (t=none or lba) (usually QEMU can guess them)\n",
185
- QEMU_ARCH_ALL)
186
-STEXI
187
-@item -hdachs @var{c},@var{h},@var{s},[,@var{t}]
188
-@findex -hdachs
189
-Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
190
-@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
191
-translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
192
-all those parameters. This option is deprecated, please use
193
-@code{-device ide-hd,cyls=c,heads=h,secs=s,...} instead.
194
-ETEXI
195
-
196
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
197
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
198
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n"
199
--
200
2.13.6
201
202
diff view generated by jsdifflib
New patch
1
From: Thomas Huth <thuth@redhat.com>
1
2
3
Looks like we forgot to announce the deprecation of these options in
4
the corresponding chapter of the qemu-doc text, so let's do that now.
5
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Markus Armbruster <armbru@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
qemu-doc.texi | 15 +++++++++++++++
12
1 file changed, 15 insertions(+)
13
14
diff --git a/qemu-doc.texi b/qemu-doc.texi
15
index XXXXXXX..XXXXXXX 100644
16
--- a/qemu-doc.texi
17
+++ b/qemu-doc.texi
18
@@ -XXX,XX +XXX,XX @@ longer be directly supported in QEMU.
19
The ``-drive if=scsi'' argument is replaced by the the
20
``-device BUS-TYPE'' argument combined with ``-drive if=none''.
21
22
+@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
23
+
24
+The drive geometry arguments are replaced by the the geometry arguments
25
+that can be specified with the ``-device'' parameter.
26
+
27
+@subsection -drive serial=... (since 2.10.0)
28
+
29
+The drive serial argument is replaced by the the serial argument
30
+that can be specified with the ``-device'' parameter.
31
+
32
+@subsection -drive addr=... (since 2.10.0)
33
+
34
+The drive addr argument is replaced by the the addr argument
35
+that can be specified with the ``-device'' parameter.
36
+
37
@subsection -net dump (since 2.10.0)
38
39
The ``--net dump'' argument is now replaced with the
40
--
41
2.13.6
42
43
diff view generated by jsdifflib
New patch
1
From: Fam Zheng <famz@redhat.com>
1
2
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
include/block/block_int.h | 1 -
7
block/io.c | 18 ------------------
8
2 files changed, 19 deletions(-)
9
10
diff --git a/include/block/block_int.h b/include/block/block_int.h
11
index XXXXXXX..XXXXXXX 100644
12
--- a/include/block/block_int.h
13
+++ b/include/block/block_int.h
14
@@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk);
15
bool blk_dev_is_medium_locked(BlockBackend *blk);
16
17
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
18
-bool bdrv_requests_pending(BlockDriverState *bs);
19
20
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
21
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
22
diff --git a/block/io.c b/block/io.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/io.c
25
+++ b/block/io.c
26
@@ -XXX,XX +XXX,XX @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
27
assert(old >= 1);
28
}
29
30
-/* Check if any requests are in-flight (including throttled requests) */
31
-bool bdrv_requests_pending(BlockDriverState *bs)
32
-{
33
- BdrvChild *child;
34
-
35
- if (atomic_read(&bs->in_flight)) {
36
- return true;
37
- }
38
-
39
- QLIST_FOREACH(child, &bs->children, next) {
40
- if (bdrv_requests_pending(child->bs)) {
41
- return true;
42
- }
43
- }
44
-
45
- return false;
46
-}
47
-
48
typedef struct {
49
Coroutine *co;
50
BlockDriverState *bs;
51
--
52
2.13.6
53
54
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Fam Zheng <famz@redhat.com>
3
---
4
block/io.c | 6 ++++++
5
1 file changed, 6 insertions(+)
1
6
7
diff --git a/block/io.c b/block/io.c
8
index XXXXXXX..XXXXXXX 100644
9
--- a/block/io.c
10
+++ b/block/io.c
11
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
12
BdrvNextIterator it;
13
GSList *aio_ctxs = NULL, *ctx;
14
15
+ /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread
16
+ * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on
17
+ * nodes in several different AioContexts, so make sure we're in the main
18
+ * context. */
19
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
20
+
21
block_job_pause_all();
22
23
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
24
--
25
2.13.6
26
27
diff view generated by jsdifflib
New patch
1
bdrv_drained_begin() doesn't increase bs->quiesce_counter recursively
2
and also doesn't notify other parent nodes of children, which both means
3
that the child nodes are not actually drained, and bdrv_drained_begin()
4
is providing useful functionality only on a single node.
1
5
6
To keep things consistent, we also shouldn't call the block driver
7
callbacks recursively.
8
9
A proper recursive drain version that provides an actually working
10
drained section for child nodes will be introduced later.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
14
---
15
block/io.c | 16 +++++++++-------
16
1 file changed, 9 insertions(+), 7 deletions(-)
17
18
diff --git a/block/io.c b/block/io.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/io.c
21
+++ b/block/io.c
22
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
23
}
24
25
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
26
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
27
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive)
28
{
29
BdrvChild *child, *tmp;
30
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
31
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
32
bdrv_coroutine_enter(bs, data.co);
33
BDRV_POLL_WHILE(bs, !data.done);
34
35
- QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
36
- bdrv_drain_invoke(child->bs, begin);
37
+ if (recursive) {
38
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
39
+ bdrv_drain_invoke(child->bs, begin, true);
40
+ }
41
}
42
}
43
44
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
45
bdrv_parent_drained_begin(bs);
46
}
47
48
- bdrv_drain_invoke(bs, true);
49
+ bdrv_drain_invoke(bs, true, false);
50
bdrv_drain_recurse(bs);
51
}
52
53
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
54
}
55
56
/* Re-enable things in child-to-parent order */
57
- bdrv_drain_invoke(bs, false);
58
+ bdrv_drain_invoke(bs, false, false);
59
bdrv_parent_drained_end(bs);
60
aio_enable_external(bdrv_get_aio_context(bs));
61
}
62
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
63
aio_context_acquire(aio_context);
64
aio_disable_external(aio_context);
65
bdrv_parent_drained_begin(bs);
66
- bdrv_drain_invoke(bs, true);
67
+ bdrv_drain_invoke(bs, true, true);
68
aio_context_release(aio_context);
69
70
if (!g_slist_find(aio_ctxs, aio_context)) {
71
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
72
73
/* Re-enable things in child-to-parent order */
74
aio_context_acquire(aio_context);
75
- bdrv_drain_invoke(bs, false);
76
+ bdrv_drain_invoke(bs, false, true);
77
bdrv_parent_drained_end(bs);
78
aio_enable_external(aio_context);
79
aio_context_release(aio_context);
80
--
81
2.13.6
82
83
diff view generated by jsdifflib
New patch
1
The existing test is for bdrv_drain_all_begin/end() only. Generalise the
2
test case so that it can be run for the other variants as well. At the
3
moment this is only bdrv_drain_begin/end(), but in a while, we'll add
4
another one.
1
5
6
Also, add a backing file to the test node to test whether the operations
7
work recursively.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
tests/test-bdrv-drain.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-----
12
1 file changed, 62 insertions(+), 7 deletions(-)
13
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/test-bdrv-drain.c
17
+++ b/tests/test-bdrv-drain.c
18
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = {
19
20
.bdrv_co_drain_begin = bdrv_test_co_drain_begin,
21
.bdrv_co_drain_end = bdrv_test_co_drain_end,
22
+
23
+ .bdrv_child_perm = bdrv_format_default_perms,
24
};
25
26
static void aio_ret_cb(void *opaque, int ret)
27
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
28
*aio_ret = ret;
29
}
30
31
-static void test_drv_cb_drain_all(void)
32
+enum drain_type {
33
+ BDRV_DRAIN_ALL,
34
+ BDRV_DRAIN,
35
+};
36
+
37
+static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
38
+{
39
+ switch (drain_type) {
40
+ case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
41
+ case BDRV_DRAIN: bdrv_drained_begin(bs); break;
42
+ default: g_assert_not_reached();
43
+ }
44
+}
45
+
46
+static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
47
+{
48
+ switch (drain_type) {
49
+ case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
50
+ case BDRV_DRAIN: bdrv_drained_end(bs); break;
51
+ default: g_assert_not_reached();
52
+ }
53
+}
54
+
55
+static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
56
{
57
BlockBackend *blk;
58
- BlockDriverState *bs;
59
- BDRVTestState *s;
60
+ BlockDriverState *bs, *backing;
61
+ BDRVTestState *s, *backing_s;
62
BlockAIOCB *acb;
63
int aio_ret;
64
65
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_all(void)
66
s = bs->opaque;
67
blk_insert_bs(blk, bs, &error_abort);
68
69
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
70
+ backing_s = backing->opaque;
71
+ bdrv_set_backing_hd(bs, backing, &error_abort);
72
+
73
/* Simple bdrv_drain_all_begin/end pair, check that CBs are called */
74
g_assert_cmpint(s->drain_count, ==, 0);
75
- bdrv_drain_all_begin();
76
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
77
+
78
+ do_drain_begin(drain_type, bs);
79
+
80
g_assert_cmpint(s->drain_count, ==, 1);
81
- bdrv_drain_all_end();
82
+ g_assert_cmpint(backing_s->drain_count, ==, !!recursive);
83
+
84
+ do_drain_end(drain_type, bs);
85
+
86
g_assert_cmpint(s->drain_count, ==, 0);
87
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
88
89
/* Now do the same while a request is pending */
90
aio_ret = -EINPROGRESS;
91
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_all(void)
92
g_assert_cmpint(aio_ret, ==, -EINPROGRESS);
93
94
g_assert_cmpint(s->drain_count, ==, 0);
95
- bdrv_drain_all_begin();
96
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
97
+
98
+ do_drain_begin(drain_type, bs);
99
+
100
g_assert_cmpint(aio_ret, ==, 0);
101
g_assert_cmpint(s->drain_count, ==, 1);
102
- bdrv_drain_all_end();
103
+ g_assert_cmpint(backing_s->drain_count, ==, !!recursive);
104
+
105
+ do_drain_end(drain_type, bs);
106
+
107
g_assert_cmpint(s->drain_count, ==, 0);
108
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
109
110
+ bdrv_unref(backing);
111
bdrv_unref(bs);
112
blk_unref(blk);
113
}
114
115
+static void test_drv_cb_drain_all(void)
116
+{
117
+ test_drv_cb_common(BDRV_DRAIN_ALL, true);
118
+}
119
+
120
+static void test_drv_cb_drain(void)
121
+{
122
+ test_drv_cb_common(BDRV_DRAIN, false);
123
+}
124
+
125
int main(int argc, char **argv)
126
{
127
bdrv_init();
128
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
129
g_test_init(&argc, &argv, NULL);
130
131
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
132
+ g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
133
134
return g_test_run();
135
}
136
--
137
2.13.6
138
139
diff view generated by jsdifflib
New patch
1
This is currently only working correctly for bdrv_drain(), not for
2
bdrv_drain_all(). Leave a comment for the drain_all case, we'll address
3
it later.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 45 insertions(+)
9
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-bdrv-drain.c
13
+++ b/tests/test-bdrv-drain.c
14
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
15
test_drv_cb_common(BDRV_DRAIN, false);
16
}
17
18
+static void test_quiesce_common(enum drain_type drain_type, bool recursive)
19
+{
20
+ BlockBackend *blk;
21
+ BlockDriverState *bs, *backing;
22
+
23
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
24
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
25
+ &error_abort);
26
+ blk_insert_bs(blk, bs, &error_abort);
27
+
28
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
29
+ bdrv_set_backing_hd(bs, backing, &error_abort);
30
+
31
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
32
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
33
+
34
+ do_drain_begin(drain_type, bs);
35
+
36
+ g_assert_cmpint(bs->quiesce_counter, ==, 1);
37
+ g_assert_cmpint(backing->quiesce_counter, ==, !!recursive);
38
+
39
+ do_drain_end(drain_type, bs);
40
+
41
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
43
+
44
+ bdrv_unref(backing);
45
+ bdrv_unref(bs);
46
+ blk_unref(blk);
47
+}
48
+
49
+static void test_quiesce_drain_all(void)
50
+{
51
+ // XXX drain_all doesn't quiesce
52
+ //test_quiesce_common(BDRV_DRAIN_ALL, true);
53
+}
54
+
55
+static void test_quiesce_drain(void)
56
+{
57
+ test_quiesce_common(BDRV_DRAIN, false);
58
+}
59
+
60
int main(int argc, char **argv)
61
{
62
bdrv_init();
63
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
64
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
65
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
66
67
+ g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
68
+ g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
69
+
70
return g_test_run();
71
}
72
--
73
2.13.6
74
75
diff view generated by jsdifflib
1
This rewrites the test case 213 to work with the new x-blockdev-create
1
Block jobs already paused themselves when their main BlockBackend
2
job rather than the old synchronous version of the command.
2
entered a drained section. This is not good enough: We also want to
3
pause a block job and may not submit new requests if, for example, the
4
mirror target node should be drained.
3
5
4
All of the test cases stay the same as before, but in order to be able
6
This implements .drained_begin/end callbacks in child_job in order to
5
to implement proper job handling, the test case is rewritten in Python.
7
consider all block nodes related to the job, and removes the
8
BlockBackend callbacks which are unnecessary now because the root of the
9
job main BlockBackend is always referenced with a child_job, too.
6
10
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
12
---
10
tests/qemu-iotests/213 | 520 +++++++++++++++++----------------------------
13
blockjob.c | 22 +++++++++-------------
11
tests/qemu-iotests/213.out | 208 +++++++++++-------
14
1 file changed, 9 insertions(+), 13 deletions(-)
12
tests/qemu-iotests/group | 4 +-
13
3 files changed, 319 insertions(+), 413 deletions(-)
14
15
15
diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213
16
diff --git a/blockjob.c b/blockjob.c
16
index XXXXXXX..XXXXXXX 100755
17
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/213
18
--- a/blockjob.c
18
+++ b/tests/qemu-iotests/213
19
+++ b/blockjob.c
19
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static char *child_job_get_parent_desc(BdrvChild *c)
20
-#!/bin/bash
21
job->id);
21
+#!/usr/bin/env python
22
}
22
#
23
23
# Test vhdx and file image creation
24
-static const BdrvChildRole child_job = {
24
#
25
- .get_parent_desc = child_job_get_parent_desc,
25
# Copyright (C) 2018 Red Hat, Inc.
26
- .stay_at_node = true,
26
#
27
-};
27
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
28
+#
29
# This program is free software; you can redistribute it and/or modify
30
# it under the terms of the GNU General Public License as published by
31
# the Free Software Foundation; either version 2 of the License, or
32
@@ -XXX,XX +XXX,XX @@
33
# along with this program. If not, see <http://www.gnu.org/licenses/>.
34
#
35
36
-# creator
37
-owner=kwolf@redhat.com
38
-
28
-
39
-seq=`basename $0`
29
-static void block_job_drained_begin(void *opaque)
40
-echo "QA output created by $seq"
30
+static void child_job_drained_begin(BdrvChild *c)
41
-
31
{
42
-here=`pwd`
32
- BlockJob *job = opaque;
43
-status=1    # failure is the default!
33
+ BlockJob *job = c->opaque;
44
-
34
block_job_pause(job);
45
-# get standard environment, filters and checks
35
}
46
-. ./common.rc
36
47
-. ./common.filter
37
-static void block_job_drained_end(void *opaque)
48
-
38
+static void child_job_drained_end(BdrvChild *c)
49
-_supported_fmt vhdx
39
{
50
-_supported_proto file
40
- BlockJob *job = opaque;
51
-_supported_os Linux
41
+ BlockJob *job = c->opaque;
52
-
42
block_job_resume(job);
53
-function do_run_qemu()
43
}
54
-{
44
55
- echo Testing: "$@"
45
-static const BlockDevOps block_job_dev_ops = {
56
- $QEMU -nographic -qmp stdio -serial none "$@"
46
- .drained_begin = block_job_drained_begin,
57
- echo
47
- .drained_end = block_job_drained_end,
58
-}
48
+static const BdrvChildRole child_job = {
59
-
49
+ .get_parent_desc = child_job_get_parent_desc,
60
-function run_qemu()
50
+ .drained_begin = child_job_drained_begin,
61
-{
51
+ .drained_end = child_job_drained_end,
62
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
52
+ .stay_at_node = true,
63
- | _filter_qemu | _filter_imgfmt \
53
};
64
- | _filter_actual_image_size
54
65
-}
55
void block_job_remove_all_bdrv(BlockJob *job)
66
-
56
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
67
-echo
57
block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
68
-echo "=== Successful image creation (defaults) ==="
58
bs->job = job;
69
-echo
59
70
-
60
- blk_set_dev_ops(blk, &block_job_dev_ops, job);
71
-size=$((128 * 1024 * 1024))
61
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
72
-
62
73
-run_qemu <<EOF
63
QLIST_INSERT_HEAD(&block_jobs, job, job_list);
74
-{ "execute": "qmp_capabilities" }
75
-{ "execute": "x-blockdev-create",
76
- "arguments": {
77
- "driver": "file",
78
- "filename": "$TEST_IMG",
79
- "size": 0
80
- }
81
-}
82
-{ "execute": "blockdev-add",
83
- "arguments": {
84
- "driver": "file",
85
- "node-name": "imgfile",
86
- "filename": "$TEST_IMG"
87
- }
88
-}
89
-{ "execute": "x-blockdev-create",
90
- "arguments": {
91
- "driver": "$IMGFMT",
92
- "file": "imgfile",
93
- "size": $size
94
- }
95
-}
96
-{ "execute": "quit" }
97
-EOF
98
-
99
-_img_info --format-specific | _filter_img_info --format-specific
100
-
101
-echo
102
-echo "=== Successful image creation (explicit defaults) ==="
103
-echo
104
-
105
-# Choose a different size to show that we got a new image
106
-size=$((64 * 1024 * 1024))
107
-
108
-run_qemu <<EOF
109
-{ "execute": "qmp_capabilities" }
110
-{ "execute": "x-blockdev-create",
111
- "arguments": {
112
- "driver": "file",
113
- "filename": "$TEST_IMG",
114
- "size": 0
115
- }
116
-}
117
-{ "execute": "x-blockdev-create",
118
- "arguments": {
119
- "driver": "$IMGFMT",
120
- "file": {
121
- "driver": "file",
122
- "filename": "$TEST_IMG"
123
- },
124
- "size": $size,
125
- "log-size": 1048576,
126
- "block-size": 8388608,
127
- "subformat": "dynamic",
128
- "block-state-zero": true
129
- }
130
-}
131
-{ "execute": "quit" }
132
-EOF
133
-
134
-_img_info --format-specific | _filter_img_info --format-specific
135
-
136
-echo
137
-echo "=== Successful image creation (with non-default options) ==="
138
-echo
139
-
140
-# Choose a different size to show that we got a new image
141
-size=$((32 * 1024 * 1024))
142
-
143
-run_qemu <<EOF
144
-{ "execute": "qmp_capabilities" }
145
-{ "execute": "x-blockdev-create",
146
- "arguments": {
147
- "driver": "file",
148
- "filename": "$TEST_IMG",
149
- "size": 0
150
- }
151
-}
152
-{ "execute": "x-blockdev-create",
153
- "arguments": {
154
- "driver": "$IMGFMT",
155
- "file": {
156
- "driver": "file",
157
- "filename": "$TEST_IMG"
158
- },
159
- "size": $size,
160
- "log-size": 8388608,
161
- "block-size": 268435456,
162
- "subformat": "fixed",
163
- "block-state-zero": false
164
- }
165
-}
166
-{ "execute": "quit" }
167
-EOF
168
-
169
-_img_info --format-specific | _filter_img_info --format-specific
170
-
171
-echo
172
-echo "=== Invalid BlockdevRef ==="
173
-echo
174
-
175
-run_qemu <<EOF
176
-{ "execute": "qmp_capabilities" }
177
-{ "execute": "x-blockdev-create",
178
- "arguments": {
179
- "driver": "$IMGFMT",
180
- "file": "this doesn't exist",
181
- "size": $size
182
- }
183
-}
184
-{ "execute": "quit" }
185
-EOF
186
-
187
-echo
188
-echo "=== Zero size ==="
189
-echo
190
-
191
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
192
-{ "execute": "qmp_capabilities" }
193
-{ "execute": "x-blockdev-create",
194
- "arguments": {
195
- "driver": "$IMGFMT",
196
- "file": "node0",
197
- "size": 0
198
- }
199
-}
200
-{ "execute": "quit" }
201
-EOF
202
-
203
-_img_info | _filter_img_info
204
-
205
-echo
206
-echo "=== Maximum size ==="
207
-echo
208
-
209
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
210
-{ "execute": "qmp_capabilities" }
211
-{ "execute": "x-blockdev-create",
212
- "arguments": {
213
- "driver": "$IMGFMT",
214
- "file": "node0",
215
- "size": 70368744177664
216
- }
217
-}
218
-{ "execute": "quit" }
219
-EOF
220
-
221
-_img_info | _filter_img_info
222
-
223
-echo
224
-echo "=== Invalid sizes ==="
225
-echo
226
-
227
-# TODO Negative image sizes aren't handled correctly, but this is a problem
228
-# with QAPI's implementation of the 'size' type and affects other commands as
229
-# well. Once this is fixed, we may want to add a test case here.
230
-
231
-# 1. 2^64 - 512
232
-# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
233
-# 3. 2^63 - 512 (generally valid, but with the image header the file will
234
-# exceed 63 bits)
235
-# 4. 2^46 + 1 (one byte more than maximum image size)
236
-
237
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
238
-{ "execute": "qmp_capabilities" }
239
-{ "execute": "x-blockdev-create",
240
- "arguments": {
241
- "driver": "$IMGFMT",
242
- "file": "node0",
243
- "size": 18446744073709551104
244
- }
245
-}
246
-{ "execute": "x-blockdev-create",
247
- "arguments": {
248
- "driver": "$IMGFMT",
249
- "file": "node0",
250
- "size": 9223372036854775808
251
- }
252
-}
253
-{ "execute": "x-blockdev-create",
254
- "arguments": {
255
- "driver": "$IMGFMT",
256
- "file": "node0",
257
- "size": 9223372036854775296
258
- }
259
-}
260
-{ "execute": "x-blockdev-create",
261
- "arguments": {
262
- "driver": "$IMGFMT",
263
- "file": "node0",
264
- "size": 70368744177665
265
- }
266
-}
267
-{ "execute": "quit" }
268
-EOF
269
-
270
-echo
271
-echo "=== Invalid block size ==="
272
-echo
273
-
274
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
275
-{ "execute": "qmp_capabilities" }
276
-{ "execute": "x-blockdev-create",
277
- "arguments": {
278
- "driver": "$IMGFMT",
279
- "file": "node0",
280
- "size": 67108864,
281
- "block-size": 1234567
282
- }
283
-}
284
-{ "execute": "x-blockdev-create",
285
- "arguments": {
286
- "driver": "$IMGFMT",
287
- "file": "node0",
288
- "size": 67108864,
289
- "block-size": 128
290
- }
291
-}
292
-{ "execute": "x-blockdev-create",
293
- "arguments": {
294
- "driver": "$IMGFMT",
295
- "file": "node0",
296
- "size": 67108864,
297
- "block-size": 3145728
298
- }
299
-}
300
-{ "execute": "x-blockdev-create",
301
- "arguments": {
302
- "driver": "$IMGFMT",
303
- "file": "node0",
304
- "size": 67108864,
305
- "block-size": 536870912
306
- }
307
-}
308
-{ "execute": "x-blockdev-create",
309
- "arguments": {
310
- "driver": "$IMGFMT",
311
- "file": "node0",
312
- "size": 67108864,
313
- "block-size": 0
314
- }
315
-}
316
-{ "execute": "quit" }
317
-EOF
318
-
319
-echo
320
-echo "=== Invalid log size ==="
321
-echo
322
-
323
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
324
-{ "execute": "qmp_capabilities" }
325
-{ "execute": "x-blockdev-create",
326
- "arguments": {
327
- "driver": "$IMGFMT",
328
- "file": "node0",
329
- "size": 67108864,
330
- "log-size": 1234567
331
- }
332
-}
333
-{ "execute": "x-blockdev-create",
334
- "arguments": {
335
- "driver": "$IMGFMT",
336
- "file": "node0",
337
- "size": 67108864,
338
- "log-size": 128
339
- }
340
-}
341
-{ "execute": "x-blockdev-create",
342
- "arguments": {
343
- "driver": "$IMGFMT",
344
- "file": "node0",
345
- "size": 67108864,
346
- "log-size": 4294967296
347
- }
348
-}
349
-{ "execute": "x-blockdev-create",
350
- "arguments": {
351
- "driver": "$IMGFMT",
352
- "file": "node0",
353
- "size": 67108864,
354
- "log-size": 0
355
- }
356
-}
357
-{ "execute": "quit" }
358
-EOF
359
-
360
-
361
-# success, all done
362
-echo "*** done"
363
-rm -f $seq.full
364
-status=0
365
+import iotests
366
+from iotests import imgfmt
367
+
368
+iotests.verify_image_format(supported_fmts=['vhdx'])
369
+iotests.verify_protocol(supported=['file'])
370
+
371
+def blockdev_create(vm, options):
372
+ result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
373
+
374
+ if 'return' in result:
375
+ assert result['return'] == {}
376
+ vm.run_job('job0')
377
+ iotests.log("")
378
+
379
+with iotests.FilePath('t.vhdx') as disk_path, \
380
+ iotests.VM() as vm:
381
+
382
+ #
383
+ # Successful image creation (defaults)
384
+ #
385
+ iotests.log("=== Successful image creation (defaults) ===")
386
+ iotests.log("")
387
+
388
+ size = 128 * 1024 * 1024
389
+
390
+ vm.launch()
391
+ blockdev_create(vm, { 'driver': 'file',
392
+ 'filename': disk_path,
393
+ 'size': 0 })
394
+
395
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
396
+ node_name='imgfile')
397
+
398
+ blockdev_create(vm, { 'driver': imgfmt,
399
+ 'file': 'imgfile',
400
+ 'size': size })
401
+ vm.shutdown()
402
+
403
+ iotests.img_info_log(disk_path)
404
+
405
+ #
406
+ # Successful image creation (explicit defaults)
407
+ #
408
+ iotests.log("=== Successful image creation (explicit defaults) ===")
409
+ iotests.log("")
410
+
411
+ # Choose a different size to show that we got a new image
412
+ size = 64 * 1024 * 1024
413
+
414
+ vm.launch()
415
+ blockdev_create(vm, { 'driver': 'file',
416
+ 'filename': disk_path,
417
+ 'size': 0 })
418
+ blockdev_create(vm, { 'driver': imgfmt,
419
+ 'file': {
420
+ 'driver': 'file',
421
+ 'filename': disk_path,
422
+ },
423
+ 'size': size,
424
+ 'log-size': 1048576,
425
+ 'block-size': 8388608,
426
+ 'subformat': 'dynamic',
427
+ 'block-state-zero': True })
428
+ vm.shutdown()
429
+
430
+ iotests.img_info_log(disk_path)
431
+
432
+ #
433
+ # Successful image creation (with non-default options)
434
+ #
435
+ iotests.log("=== Successful image creation (with non-default options) ===")
436
+ iotests.log("")
437
+
438
+ # Choose a different size to show that we got a new image
439
+ size = 32 * 1024 * 1024
440
+
441
+ vm.launch()
442
+ blockdev_create(vm, { 'driver': 'file',
443
+ 'filename': disk_path,
444
+ 'size': 0 })
445
+ blockdev_create(vm, { 'driver': imgfmt,
446
+ 'file': {
447
+ 'driver': 'file',
448
+ 'filename': disk_path,
449
+ },
450
+ 'size': size,
451
+ 'log-size': 8388608,
452
+ 'block-size': 268435456,
453
+ 'subformat': 'fixed',
454
+ 'block-state-zero': False })
455
+ vm.shutdown()
456
+
457
+ iotests.img_info_log(disk_path)
458
+
459
+ #
460
+ # Invalid BlockdevRef
461
+ #
462
+ iotests.log("=== Invalid BlockdevRef ===")
463
+ iotests.log("")
464
+
465
+ vm.launch()
466
+ blockdev_create(vm, { 'driver': imgfmt,
467
+ 'file': "this doesn't exist",
468
+ 'size': size })
469
+ vm.shutdown()
470
+
471
+ #
472
+ # Zero size
473
+ #
474
+ iotests.log("=== Zero size ===")
475
+ iotests.log("")
476
+
477
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
478
+ vm.launch()
479
+ blockdev_create(vm, { 'driver': imgfmt,
480
+ 'file': 'node0',
481
+ 'size': 0 })
482
+ vm.shutdown()
483
+
484
+ iotests.img_info_log(disk_path)
485
+
486
+ #
487
+ # Maximum size
488
+ #
489
+ iotests.log("=== Maximum size ===")
490
+ iotests.log("")
491
+
492
+ vm.launch()
493
+ blockdev_create(vm, { 'driver': imgfmt,
494
+ 'file': 'node0',
495
+ 'size': 70368744177664 })
496
+ vm.shutdown()
497
+
498
+ iotests.img_info_log(disk_path)
499
+
500
+ #
501
+ # Invalid sizes
502
+ #
503
+
504
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
505
+ # with QAPI's implementation of the 'size' type and affects other commands
506
+ # as well. Once this is fixed, we may want to add a test case here.
507
+
508
+ # 1. 2^64 - 512
509
+ # 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
510
+ # 3. 2^63 - 512 (generally valid, but with the image header the file will
511
+ # exceed 63 bits)
512
+ # 4. 2^46 + 1 (one byte more than maximum image size)
513
+
514
+ iotests.log("=== Invalid sizes ===")
515
+ iotests.log("")
516
+
517
+ vm.launch()
518
+ for size in [ 18446744073709551104, 9223372036854775808,
519
+ 9223372036854775296, 70368744177665 ]:
520
+ blockdev_create(vm, { 'driver': imgfmt,
521
+ 'file': 'node0',
522
+ 'size': size })
523
+ vm.shutdown()
524
+
525
+ #
526
+ # Invalid block size
527
+ #
528
+ iotests.log("=== Invalid block size ===")
529
+ iotests.log("")
530
+
531
+ vm.launch()
532
+ for bsize in [ 1234567, 128, 3145728, 536870912, 0 ]:
533
+ blockdev_create(vm, { 'driver': imgfmt,
534
+ 'file': 'node0',
535
+ 'size': 67108864,
536
+ 'block-size': bsize })
537
+ vm.shutdown()
538
+
539
+ #
540
+ # Invalid log size
541
+ #
542
+ iotests.log("=== Invalid log size ===")
543
+ iotests.log("")
544
+
545
+ vm.launch()
546
+ for lsize in [ 1234567, 128, 4294967296, 0 ]:
547
+ blockdev_create(vm, { 'driver': imgfmt,
548
+ 'file': 'node0',
549
+ 'size': 67108864,
550
+ 'log-size': lsize })
551
+ vm.shutdown()
552
diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out
553
index XXXXXXX..XXXXXXX 100644
554
--- a/tests/qemu-iotests/213.out
555
+++ b/tests/qemu-iotests/213.out
556
@@ -XXX,XX +XXX,XX @@
557
-QA output created by 213
558
-
559
=== Successful image creation (defaults) ===
560
561
-Testing:
562
-QMP_VERSION
563
-{"return": {}}
564
-{"return": {}}
565
-{"return": {}}
566
-{"return": {}}
567
-{"return": {}}
568
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
569
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
570
+{u'return': {}}
571
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
572
+{u'return': {}}
573
+
574
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}
575
+{u'return': {}}
576
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'imgfile', 'size': 134217728}}}
577
+{u'return': {}}
578
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
579
+{u'return': {}}
580
581
-image: TEST_DIR/t.IMGFMT
582
+image: TEST_IMG
583
file format: IMGFMT
584
virtual size: 128M (134217728 bytes)
585
+cluster_size: 8388608
586
587
=== Successful image creation (explicit defaults) ===
588
589
-Testing:
590
-QMP_VERSION
591
-{"return": {}}
592
-{"return": {}}
593
-{"return": {}}
594
-{"return": {}}
595
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
596
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
597
+{u'return': {}}
598
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
599
+{u'return': {}}
600
601
-image: TEST_DIR/t.IMGFMT
602
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 8388608, 'driver': 'vhdx', 'subformat': 'dynamic', 'log-size': 1048576, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': True, 'size': 67108864}}}
603
+{u'return': {}}
604
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
605
+{u'return': {}}
606
+
607
+image: TEST_IMG
608
file format: IMGFMT
609
virtual size: 64M (67108864 bytes)
610
+cluster_size: 8388608
611
612
=== Successful image creation (with non-default options) ===
613
614
-Testing:
615
-QMP_VERSION
616
-{"return": {}}
617
-{"return": {}}
618
-{"return": {}}
619
-{"return": {}}
620
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
621
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
622
+{u'return': {}}
623
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
624
+{u'return': {}}
625
+
626
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 268435456, 'driver': 'vhdx', 'subformat': 'fixed', 'log-size': 8388608, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': False, 'size': 33554432}}}
627
+{u'return': {}}
628
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
629
+{u'return': {}}
630
631
-image: TEST_DIR/t.IMGFMT
632
+image: TEST_IMG
633
file format: IMGFMT
634
virtual size: 32M (33554432 bytes)
635
+cluster_size: 268435456
636
637
=== Invalid BlockdevRef ===
638
639
-Testing:
640
-QMP_VERSION
641
-{"return": {}}
642
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
643
-{"return": {}}
644
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
645
-
646
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': "this doesn't exist", 'size': 33554432}}}
647
+{u'return': {}}
648
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
649
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
650
+{u'return': {}}
651
652
=== Zero size ===
653
654
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
655
-QMP_VERSION
656
-{"return": {}}
657
-{"return": {}}
658
-{"return": {}}
659
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
660
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 0}}}
661
+{u'return': {}}
662
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
663
+{u'return': {}}
664
665
-image: TEST_DIR/t.IMGFMT
666
+image: TEST_IMG
667
file format: IMGFMT
668
virtual size: 0 (0 bytes)
669
+cluster_size: 8388608
670
671
=== Maximum size ===
672
673
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
674
-QMP_VERSION
675
-{"return": {}}
676
-{"return": {}}
677
-{"return": {}}
678
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
679
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177664}}}
680
+{u'return': {}}
681
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
682
+{u'return': {}}
683
684
-image: TEST_DIR/t.IMGFMT
685
+image: TEST_IMG
686
file format: IMGFMT
687
virtual size: 64T (70368744177664 bytes)
688
+cluster_size: 67108864
689
690
=== Invalid sizes ===
691
692
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
693
-QMP_VERSION
694
-{"return": {}}
695
-{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
696
-{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
697
-{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
698
-{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
699
-{"return": {}}
700
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
701
-
702
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 18446744073709551104L}}}
703
+{u'return': {}}
704
+Job failed: Image size too large; max of 64TB
705
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
706
+{u'return': {}}
707
+
708
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775808L}}}
709
+{u'return': {}}
710
+Job failed: Image size too large; max of 64TB
711
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
712
+{u'return': {}}
713
+
714
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775296}}}
715
+{u'return': {}}
716
+Job failed: Image size too large; max of 64TB
717
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
718
+{u'return': {}}
719
+
720
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177665}}}
721
+{u'return': {}}
722
+Job failed: Image size too large; max of 64TB
723
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
724
+{u'return': {}}
725
726
=== Invalid block size ===
727
728
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
729
-QMP_VERSION
730
-{"return": {}}
731
-{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
732
-{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
733
-{"error": {"class": "GenericError", "desc": "Block size must be a power of two"}}
734
-{"error": {"class": "GenericError", "desc": "Block size must not exceed 268435456"}}
735
-{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
736
-{"return": {}}
737
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
738
-
739
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 1234567, 'file': 'node0', 'size': 67108864}}}
740
+{u'return': {}}
741
+Job failed: Block size must be a multiple of 1 MB
742
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
743
+{u'return': {}}
744
+
745
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 128, 'file': 'node0', 'size': 67108864}}}
746
+{u'return': {}}
747
+Job failed: Block size must be a multiple of 1 MB
748
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
749
+{u'return': {}}
750
+
751
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 3145728, 'file': 'node0', 'size': 67108864}}}
752
+{u'return': {}}
753
+Job failed: Block size must be a power of two
754
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
755
+{u'return': {}}
756
+
757
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 536870912, 'file': 'node0', 'size': 67108864}}}
758
+{u'return': {}}
759
+Job failed: Block size must not exceed 268435456
760
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
761
+{u'return': {}}
762
+
763
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 0, 'file': 'node0', 'size': 67108864}}}
764
+{u'return': {}}
765
+Job failed: Block size must be a multiple of 1 MB
766
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
767
+{u'return': {}}
768
769
=== Invalid log size ===
770
771
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
772
-QMP_VERSION
773
-{"return": {}}
774
-{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
775
-{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
776
-{"error": {"class": "GenericError", "desc": "Log size must be smaller than 4 GB"}}
777
-{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
778
-{"return": {}}
779
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
780
-
781
-*** done
782
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 1234567, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
783
+{u'return': {}}
784
+Job failed: Log size must be a multiple of 1 MB
785
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
786
+{u'return': {}}
787
+
788
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 128, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
789
+{u'return': {}}
790
+Job failed: Log size must be a multiple of 1 MB
791
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
792
+{u'return': {}}
793
+
794
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 4294967296, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
795
+{u'return': {}}
796
+Job failed: Log size must be smaller than 4 GB
797
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
798
+{u'return': {}}
799
+
800
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 0, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
801
+{u'return': {}}
802
+Job failed: Log size must be a multiple of 1 MB
803
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
804
+{u'return': {}}
805
+
806
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
807
index XXXXXXX..XXXXXXX 100644
808
--- a/tests/qemu-iotests/group
809
+++ b/tests/qemu-iotests/group
810
@@ -XXX,XX +XXX,XX @@
811
210 rw auto
812
211 rw auto quick
813
212 rw auto quick
814
-# TODO The following commented out tests need to be reworked to work
815
-# with the x-blockdev-create job
816
-#213 rw auto quick
817
+213 rw auto quick
818
214 rw auto
819
215 rw auto quick
820
216 rw auto quick
821
--
64
--
822
2.13.6
65
2.13.6
823
66
824
67
diff view generated by jsdifflib
1
This changes the x-blockdev-create QMP command so that it doesn't block
1
Block jobs must be paused if any of the involved nodes are drained.
2
the monitor and the main loop any more, but starts a background job that
3
performs the image creation.
4
5
The basic job as implemented here is all that is necessary to make image
6
creation asynchronous and to provide a QMP interface that can be marked
7
stable, but it still lacks a few features that jobs usually provide: The
8
job will ignore pause commands and it doesn't publish more than very
9
basic progress yet (total-progress is 1 and current-progress advances
10
from 0 to 1 when the driver callbacks returns). These features can be
11
added later without breaking compatibility.
12
2
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Jeff Cody <jcody@redhat.com>
16
---
4
---
17
qapi/block-core.json | 14 ++++++----
5
tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++
18
qapi/job.json | 4 ++-
6
1 file changed, 121 insertions(+)
19
block/create.c | 67 +++++++++++++++++++++++++++++++++---------------
20
tests/qemu-iotests/group | 14 +++++-----
21
4 files changed, 66 insertions(+), 33 deletions(-)
22
7
23
diff --git a/qapi/block-core.json b/qapi/block-core.json
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
24
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
25
--- a/qapi/block-core.json
10
--- a/tests/test-bdrv-drain.c
26
+++ b/qapi/block-core.json
11
+++ b/tests/test-bdrv-drain.c
27
@@ -XXX,XX +XXX,XX @@
12
@@ -XXX,XX +XXX,XX @@
28
##
29
# @x-blockdev-create:
30
#
31
-# Create an image format on a given node.
32
-# TODO Replace with something asynchronous (block job?)
33
+# Starts a job to create an image format on a given node. The job is
34
+# automatically finalized, but a manual job-dismiss is required.
35
#
36
-# Since: 2.12
37
+# @job-id: Identifier for the newly created job.
38
+#
39
+# @options: Options for the image creation.
40
+#
41
+# Since: 3.0
42
##
43
{ 'command': 'x-blockdev-create',
44
- 'data': 'BlockdevCreateOptions',
45
- 'boxed': true }
46
+ 'data': { 'job-id': 'str',
47
+ 'options': 'BlockdevCreateOptions' } }
48
49
##
50
# @blockdev-open-tray:
51
diff --git a/qapi/job.json b/qapi/job.json
52
index XXXXXXX..XXXXXXX 100644
53
--- a/qapi/job.json
54
+++ b/qapi/job.json
55
@@ -XXX,XX +XXX,XX @@
56
#
57
# @backup: drive backup job type, see "drive-backup"
58
#
59
+# @create: image creation job type, see "x-blockdev-create" (since 3.0)
60
+#
61
# Since: 1.7
62
##
63
{ 'enum': 'JobType',
64
- 'data': ['commit', 'stream', 'mirror', 'backup'] }
65
+ 'data': ['commit', 'stream', 'mirror', 'backup', 'create'] }
66
67
##
68
# @JobStatus:
69
diff --git a/block/create.c b/block/create.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/create.c
72
+++ b/block/create.c
73
@@ -XXX,XX +XXX,XX @@
74
13
75
#include "qemu/osdep.h"
14
#include "qemu/osdep.h"
76
#include "block/block_int.h"
15
#include "block/block.h"
77
+#include "qemu/job.h"
16
+#include "block/blockjob_int.h"
78
#include "qapi/qapi-commands-block-core.h"
17
#include "sysemu/block-backend.h"
79
+#include "qapi/qapi-visit-block-core.h"
80
+#include "qapi/clone-visitor.h"
81
#include "qapi/error.h"
18
#include "qapi/error.h"
82
19
83
-typedef struct BlockdevCreateCo {
20
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
84
+typedef struct BlockdevCreateJob {
21
test_quiesce_common(BDRV_DRAIN, false);
85
+ Job common;
22
}
86
BlockDriver *drv;
23
87
BlockdevCreateOptions *opts;
88
int ret;
89
- Error **errp;
90
-} BlockdevCreateCo;
91
+ Error *err;
92
+} BlockdevCreateJob;
93
94
-static void coroutine_fn bdrv_co_create_co_entry(void *opaque)
95
+static void blockdev_create_complete(Job *job, void *opaque)
96
{
97
- BlockdevCreateCo *cco = opaque;
98
- cco->ret = cco->drv->bdrv_co_create(cco->opts, cco->errp);
99
+ BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
100
+
24
+
101
+ job_completed(job, s->ret, s->err);
25
+typedef struct TestBlockJob {
102
}
26
+ BlockJob common;
103
27
+ bool should_complete;
104
-void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp)
28
+} TestBlockJob;
105
+static void coroutine_fn blockdev_create_run(void *opaque)
106
{
107
+ BlockdevCreateJob *s = opaque;
108
+
29
+
109
+ job_progress_set_remaining(&s->common, 1);
30
+static void test_job_completed(BlockJob *job, void *opaque)
110
+ s->ret = s->drv->bdrv_co_create(s->opts, &s->err);
31
+{
111
+ job_progress_update(&s->common, 1);
32
+ block_job_completed(job, 0);
112
+
113
+ qapi_free_BlockdevCreateOptions(s->opts);
114
+ job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL);
115
+}
33
+}
116
+
34
+
117
+static const JobDriver blockdev_create_job_driver = {
35
+static void coroutine_fn test_job_start(void *opaque)
118
+ .instance_size = sizeof(BlockdevCreateJob),
36
+{
119
+ .job_type = JOB_TYPE_CREATE,
37
+ TestBlockJob *s = opaque;
120
+ .start = blockdev_create_run,
38
+
39
+ while (!s->should_complete) {
40
+ block_job_sleep_ns(&s->common, 100000);
41
+ }
42
+
43
+ block_job_defer_to_main_loop(&s->common, test_job_completed, NULL);
44
+}
45
+
46
+static void test_job_complete(BlockJob *job, Error **errp)
47
+{
48
+ TestBlockJob *s = container_of(job, TestBlockJob, common);
49
+ s->should_complete = true;
50
+}
51
+
52
+BlockJobDriver test_job_driver = {
53
+ .instance_size = sizeof(TestBlockJob),
54
+ .start = test_job_start,
55
+ .complete = test_job_complete,
121
+};
56
+};
122
+
57
+
123
+void qmp_x_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
58
+static void test_blockjob_common(enum drain_type drain_type)
124
+ Error **errp)
125
+{
59
+{
126
+ BlockdevCreateJob *s;
60
+ BlockBackend *blk_src, *blk_target;
127
const char *fmt = BlockdevDriver_str(options->driver);
61
+ BlockDriverState *src, *target;
128
BlockDriver *drv = bdrv_find_format(fmt);
62
+ BlockJob *job;
129
- Coroutine *co;
63
+ int ret;
130
- BlockdevCreateCo cco;
131
132
/* If the driver is in the schema, we know that it exists. But it may not
133
* be whitelisted. */
134
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp)
135
return;
136
}
137
138
- /* Call callback if it exists */
139
+ /* Error out if the driver doesn't support .bdrv_co_create */
140
if (!drv->bdrv_co_create) {
141
error_setg(errp, "Driver does not support blockdev-create");
142
return;
143
}
144
145
- cco = (BlockdevCreateCo) {
146
- .drv = drv,
147
- .opts = options,
148
- .ret = -EINPROGRESS,
149
- .errp = errp,
150
- };
151
-
152
- co = qemu_coroutine_create(bdrv_co_create_co_entry, &cco);
153
- qemu_coroutine_enter(co);
154
- while (cco.ret == -EINPROGRESS) {
155
- aio_poll(qemu_get_aio_context(), true);
156
+ /* Create the block job */
157
+ /* TODO Running in the main context. Block drivers need to error out or add
158
+ * locking when they use a BDS in a different AioContext. */
159
+ s = job_create(job_id, &blockdev_create_job_driver, NULL,
160
+ qemu_get_aio_context(), JOB_DEFAULT | JOB_MANUAL_DISMISS,
161
+ NULL, NULL, errp);
162
+ if (!s) {
163
+ return;
164
}
165
+
64
+
166
+ s->drv = drv,
65
+ src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR,
167
+ s->opts = QAPI_CLONE(BlockdevCreateOptions, options),
66
+ &error_abort);
67
+ blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
68
+ blk_insert_bs(blk_src, src, &error_abort);
168
+
69
+
169
+ job_start(&s->common);
70
+ target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
71
+ &error_abort);
72
+ blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
73
+ blk_insert_bs(blk_target, target, &error_abort);
74
+
75
+ job = block_job_create("job0", &test_job_driver, src, 0, BLK_PERM_ALL, 0,
76
+ 0, NULL, NULL, &error_abort);
77
+ block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
78
+ block_job_start(job);
79
+
80
+ g_assert_cmpint(job->pause_count, ==, 0);
81
+ g_assert_false(job->paused);
82
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
83
+
84
+ do_drain_begin(drain_type, src);
85
+
86
+ if (drain_type == BDRV_DRAIN_ALL) {
87
+ /* bdrv_drain_all() drains both src and target, and involves an
88
+ * additional block_job_pause_all() */
89
+ g_assert_cmpint(job->pause_count, ==, 3);
90
+ } else {
91
+ g_assert_cmpint(job->pause_count, ==, 1);
92
+ }
93
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
94
+ /* g_assert_true(job->paused); */
95
+ g_assert_false(job->busy); /* The job is paused */
96
+
97
+ do_drain_end(drain_type, src);
98
+
99
+ g_assert_cmpint(job->pause_count, ==, 0);
100
+ g_assert_false(job->paused);
101
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
102
+
103
+ do_drain_begin(drain_type, target);
104
+
105
+ if (drain_type == BDRV_DRAIN_ALL) {
106
+ /* bdrv_drain_all() drains both src and target, and involves an
107
+ * additional block_job_pause_all() */
108
+ g_assert_cmpint(job->pause_count, ==, 3);
109
+ } else {
110
+ g_assert_cmpint(job->pause_count, ==, 1);
111
+ }
112
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
113
+ /* g_assert_true(job->paused); */
114
+ g_assert_false(job->busy); /* The job is paused */
115
+
116
+ do_drain_end(drain_type, target);
117
+
118
+ g_assert_cmpint(job->pause_count, ==, 0);
119
+ g_assert_false(job->paused);
120
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
121
+
122
+ ret = block_job_complete_sync(job, &error_abort);
123
+ g_assert_cmpint(ret, ==, 0);
124
+
125
+ blk_unref(blk_src);
126
+ blk_unref(blk_target);
127
+ bdrv_unref(src);
128
+ bdrv_unref(target);
129
+}
130
+
131
+static void test_blockjob_drain_all(void)
132
+{
133
+ test_blockjob_common(BDRV_DRAIN_ALL);
134
+}
135
+
136
+static void test_blockjob_drain(void)
137
+{
138
+ test_blockjob_common(BDRV_DRAIN);
139
+}
140
+
141
int main(int argc, char **argv)
142
{
143
bdrv_init();
144
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
145
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
146
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
147
148
+ g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
149
+ g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
150
+
151
return g_test_run();
170
}
152
}
171
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
172
index XXXXXXX..XXXXXXX 100644
173
--- a/tests/qemu-iotests/group
174
+++ b/tests/qemu-iotests/group
175
@@ -XXX,XX +XXX,XX @@
176
203 rw auto migration
177
204 rw auto quick
178
205 rw auto quick
179
-206 rw auto
180
-207 rw auto
181
+# TODO The following commented out tests need to be reworked to work
182
+# with the x-blockdev-create job
183
+#206 rw auto
184
+#207 rw auto
185
208 rw auto quick
186
209 rw auto quick
187
-210 rw auto
188
-211 rw auto quick
189
-212 rw auto quick
190
-213 rw auto quick
191
+#210 rw auto
192
+#211 rw auto quick
193
+#212 rw auto quick
194
+#213 rw auto quick
195
214 rw auto
196
215 rw auto quick
197
216 rw auto quick
198
--
153
--
199
2.13.6
154
2.13.6
200
155
201
156
diff view generated by jsdifflib
1
This rewrites the test case 212 to work with the new x-blockdev-create
1
Block jobs are already paused using the BdrvChildRole drain callbacks,
2
job rather than the old synchronous version of the command.
2
so we don't need an additional block_job_pause_all() call.
3
4
All of the test cases stay the same as before, but in order to be able
5
to implement proper job handling, the test case is rewritten in Python.
6
3
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
5
---
10
tests/qemu-iotests/212 | 483 +++++++++++++++++----------------------------
6
block/io.c | 4 ----
11
tests/qemu-iotests/212.out | 191 +++++++++++-------
7
tests/test-bdrv-drain.c | 10 ++++------
12
tests/qemu-iotests/group | 2 +-
8
2 files changed, 4 insertions(+), 10 deletions(-)
13
3 files changed, 295 insertions(+), 381 deletions(-)
14
9
15
diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212
10
diff --git a/block/io.c b/block/io.c
16
index XXXXXXX..XXXXXXX 100755
11
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/212
12
--- a/block/io.c
18
+++ b/tests/qemu-iotests/212
13
+++ b/block/io.c
19
@@ -XXX,XX +XXX,XX @@
14
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
20
-#!/bin/bash
15
* context. */
21
+#!/usr/bin/env python
16
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
22
#
17
23
# Test parallels and file image creation
18
- block_job_pause_all();
24
#
25
# Copyright (C) 2018 Red Hat, Inc.
26
#
27
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
28
+#
29
# This program is free software; you can redistribute it and/or modify
30
# it under the terms of the GNU General Public License as published by
31
# the Free Software Foundation; either version 2 of the License, or
32
@@ -XXX,XX +XXX,XX @@
33
# along with this program. If not, see <http://www.gnu.org/licenses/>.
34
#
35
36
-# creator
37
-owner=kwolf@redhat.com
38
-
19
-
39
-seq=`basename $0`
20
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
40
-echo "QA output created by $seq"
21
AioContext *aio_context = bdrv_get_aio_context(bs);
22
23
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
24
aio_enable_external(aio_context);
25
aio_context_release(aio_context);
26
}
41
-
27
-
42
-here=`pwd`
28
- block_job_resume_all();
43
-status=1    # failure is the default!
29
}
44
-
30
45
-# get standard environment, filters and checks
31
void bdrv_drain_all(void)
46
-. ./common.rc
32
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
47
-. ./common.filter
48
-
49
-_supported_fmt parallels
50
-_supported_proto file
51
-_supported_os Linux
52
-
53
-function do_run_qemu()
54
-{
55
- echo Testing: "$@"
56
- $QEMU -nographic -qmp stdio -serial none "$@"
57
- echo
58
-}
59
-
60
-function run_qemu()
61
-{
62
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
63
- | _filter_qemu | _filter_imgfmt \
64
- | _filter_actual_image_size
65
-}
66
-
67
-echo
68
-echo "=== Successful image creation (defaults) ==="
69
-echo
70
-
71
-size=$((128 * 1024 * 1024))
72
-
73
-run_qemu <<EOF
74
-{ "execute": "qmp_capabilities" }
75
-{ "execute": "x-blockdev-create",
76
- "arguments": {
77
- "driver": "file",
78
- "filename": "$TEST_IMG",
79
- "size": 0
80
- }
81
-}
82
-{ "execute": "blockdev-add",
83
- "arguments": {
84
- "driver": "file",
85
- "node-name": "imgfile",
86
- "filename": "$TEST_IMG"
87
- }
88
-}
89
-{ "execute": "x-blockdev-create",
90
- "arguments": {
91
- "driver": "$IMGFMT",
92
- "file": "imgfile",
93
- "size": $size
94
- }
95
-}
96
-{ "execute": "quit" }
97
-EOF
98
-
99
-_img_info --format-specific | _filter_img_info --format-specific
100
-
101
-echo
102
-echo "=== Successful image creation (explicit defaults) ==="
103
-echo
104
-
105
-# Choose a different size to show that we got a new image
106
-size=$((64 * 1024 * 1024))
107
-
108
-run_qemu <<EOF
109
-{ "execute": "qmp_capabilities" }
110
-{ "execute": "x-blockdev-create",
111
- "arguments": {
112
- "driver": "file",
113
- "filename": "$TEST_IMG",
114
- "size": 0
115
- }
116
-}
117
-{ "execute": "x-blockdev-create",
118
- "arguments": {
119
- "driver": "$IMGFMT",
120
- "file": {
121
- "driver": "file",
122
- "filename": "$TEST_IMG"
123
- },
124
- "size": $size,
125
- "cluster-size": 1048576
126
- }
127
-}
128
-{ "execute": "quit" }
129
-EOF
130
-
131
-_img_info --format-specific | _filter_img_info --format-specific
132
-
133
-echo
134
-echo "=== Successful image creation (with non-default options) ==="
135
-echo
136
-
137
-# Choose a different size to show that we got a new image
138
-size=$((32 * 1024 * 1024))
139
-
140
-run_qemu <<EOF
141
-{ "execute": "qmp_capabilities" }
142
-{ "execute": "x-blockdev-create",
143
- "arguments": {
144
- "driver": "file",
145
- "filename": "$TEST_IMG",
146
- "size": 0
147
- }
148
-}
149
-{ "execute": "x-blockdev-create",
150
- "arguments": {
151
- "driver": "$IMGFMT",
152
- "file": {
153
- "driver": "file",
154
- "filename": "$TEST_IMG"
155
- },
156
- "size": $size,
157
- "cluster-size": 65536
158
- }
159
-}
160
-{ "execute": "quit" }
161
-EOF
162
-
163
-_img_info --format-specific | _filter_img_info --format-specific
164
-
165
-echo
166
-echo "=== Invalid BlockdevRef ==="
167
-echo
168
-
169
-run_qemu <<EOF
170
-{ "execute": "qmp_capabilities" }
171
-{ "execute": "x-blockdev-create",
172
- "arguments": {
173
- "driver": "$IMGFMT",
174
- "file": "this doesn't exist",
175
- "size": $size
176
- }
177
-}
178
-{ "execute": "quit" }
179
-EOF
180
-
181
-echo
182
-echo "=== Zero size ==="
183
-echo
184
-
185
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
186
-{ "execute": "qmp_capabilities" }
187
-{ "execute": "x-blockdev-create",
188
- "arguments": {
189
- "driver": "$IMGFMT",
190
- "file": "node0",
191
- "size": 0
192
- }
193
-}
194
-{ "execute": "quit" }
195
-EOF
196
-
197
-_img_info | _filter_img_info
198
-
199
-echo
200
-echo "=== Maximum size ==="
201
-echo
202
-
203
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
204
-{ "execute": "qmp_capabilities" }
205
-{ "execute": "x-blockdev-create",
206
- "arguments": {
207
- "driver": "$IMGFMT",
208
- "file": "node0",
209
- "size": 4503599627369984
210
- }
211
-}
212
-{ "execute": "quit" }
213
-EOF
214
-
215
-_img_info | _filter_img_info
216
-
217
-echo
218
-echo "=== Invalid sizes ==="
219
-echo
220
-
221
-# TODO Negative image sizes aren't handled correctly, but this is a problem
222
-# with QAPI's implementation of the 'size' type and affects other commands as
223
-# well. Once this is fixed, we may want to add a test case here.
224
-
225
-# 1. Misaligned image size
226
-# 2. 2^64 - 512
227
-# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
228
-# 4. 2^63 - 512 (generally valid, but with the image header the file will
229
-# exceed 63 bits)
230
-# 5. 2^52 (512 bytes more than maximum image size)
231
-
232
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
233
-{ "execute": "qmp_capabilities" }
234
-{ "execute": "x-blockdev-create",
235
- "arguments": {
236
- "driver": "$IMGFMT",
237
- "file": "node0",
238
- "size": 1234
239
- }
240
-}
241
-{ "execute": "x-blockdev-create",
242
- "arguments": {
243
- "driver": "$IMGFMT",
244
- "file": "node0",
245
- "size": 18446744073709551104
246
- }
247
-}
248
-{ "execute": "x-blockdev-create",
249
- "arguments": {
250
- "driver": "$IMGFMT",
251
- "file": "node0",
252
- "size": 9223372036854775808
253
- }
254
-}
255
-{ "execute": "x-blockdev-create",
256
- "arguments": {
257
- "driver": "$IMGFMT",
258
- "file": "node0",
259
- "size": 9223372036854775296
260
- }
261
-}
262
-{ "execute": "x-blockdev-create",
263
- "arguments": {
264
- "driver": "$IMGFMT",
265
- "file": "node0",
266
- "size": 4503599627370497
267
- }
268
-}
269
-{ "execute": "quit" }
270
-EOF
271
-
272
-echo
273
-echo "=== Invalid cluster size ==="
274
-echo
275
-
276
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
277
-{ "execute": "qmp_capabilities" }
278
-{ "execute": "x-blockdev-create",
279
- "arguments": {
280
- "driver": "$IMGFMT",
281
- "file": "node0",
282
- "size": 67108864,
283
- "cluster-size": 1234
284
- }
285
-}
286
-{ "execute": "x-blockdev-create",
287
- "arguments": {
288
- "driver": "$IMGFMT",
289
- "file": "node0",
290
- "size": 67108864,
291
- "cluster-size": 128
292
- }
293
-}
294
-{ "execute": "x-blockdev-create",
295
- "arguments": {
296
- "driver": "$IMGFMT",
297
- "file": "node0",
298
- "size": 67108864,
299
- "cluster-size": 4294967296
300
- }
301
-}
302
-{ "execute": "x-blockdev-create",
303
- "arguments": {
304
- "driver": "$IMGFMT",
305
- "file": "node0",
306
- "size": 67108864,
307
- "cluster-size": 9223372036854775808
308
- }
309
-}
310
-{ "execute": "x-blockdev-create",
311
- "arguments": {
312
- "driver": "$IMGFMT",
313
- "file": "node0",
314
- "size": 67108864,
315
- "cluster-size": 18446744073709551104
316
- }
317
-}
318
-{ "execute": "x-blockdev-create",
319
- "arguments": {
320
- "driver": "$IMGFMT",
321
- "file": "node0",
322
- "size": 67108864,
323
- "cluster-size": 0
324
- }
325
-}
326
-{ "execute": "x-blockdev-create",
327
- "arguments": {
328
- "driver": "$IMGFMT",
329
- "file": "node0",
330
- "size": 281474976710656,
331
- "cluster-size": 512
332
- }
333
-}
334
-{ "execute": "quit" }
335
-EOF
336
-
337
-
338
-# success, all done
339
-echo "*** done"
340
-rm -f $seq.full
341
-status=0
342
+import iotests
343
+from iotests import imgfmt
344
+
345
+iotests.verify_image_format(supported_fmts=['parallels'])
346
+iotests.verify_protocol(supported=['file'])
347
+
348
+def blockdev_create(vm, options):
349
+ result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
350
+
351
+ if 'return' in result:
352
+ assert result['return'] == {}
353
+ vm.run_job('job0')
354
+ iotests.log("")
355
+
356
+with iotests.FilePath('t.parallels') as disk_path, \
357
+ iotests.VM() as vm:
358
+
359
+ #
360
+ # Successful image creation (defaults)
361
+ #
362
+ iotests.log("=== Successful image creation (defaults) ===")
363
+ iotests.log("")
364
+
365
+ size = 128 * 1024 * 1024
366
+
367
+ vm.launch()
368
+ blockdev_create(vm, { 'driver': 'file',
369
+ 'filename': disk_path,
370
+ 'size': 0 })
371
+
372
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
373
+ node_name='imgfile')
374
+
375
+ blockdev_create(vm, { 'driver': imgfmt,
376
+ 'file': 'imgfile',
377
+ 'size': size })
378
+ vm.shutdown()
379
+
380
+ iotests.img_info_log(disk_path)
381
+
382
+ #
383
+ # Successful image creation (explicit defaults)
384
+ #
385
+ iotests.log("=== Successful image creation (explicit defaults) ===")
386
+ iotests.log("")
387
+
388
+ # Choose a different size to show that we got a new image
389
+ size = 64 * 1024 * 1024
390
+
391
+ vm.launch()
392
+ blockdev_create(vm, { 'driver': 'file',
393
+ 'filename': disk_path,
394
+ 'size': 0 })
395
+ blockdev_create(vm, { 'driver': imgfmt,
396
+ 'file': {
397
+ 'driver': 'file',
398
+ 'filename': disk_path,
399
+ },
400
+ 'size': size,
401
+ 'cluster-size': 1048576 })
402
+ vm.shutdown()
403
+
404
+ iotests.img_info_log(disk_path)
405
+
406
+ #
407
+ # Successful image creation (with non-default options)
408
+ #
409
+ iotests.log("=== Successful image creation (with non-default options) ===")
410
+ iotests.log("")
411
+
412
+ # Choose a different size to show that we got a new image
413
+ size = 32 * 1024 * 1024
414
+
415
+ vm.launch()
416
+ blockdev_create(vm, { 'driver': 'file',
417
+ 'filename': disk_path,
418
+ 'size': 0 })
419
+ blockdev_create(vm, { 'driver': imgfmt,
420
+ 'file': {
421
+ 'driver': 'file',
422
+ 'filename': disk_path,
423
+ },
424
+ 'size': size,
425
+ 'cluster-size': 65536 })
426
+ vm.shutdown()
427
+
428
+ iotests.img_info_log(disk_path)
429
+
430
+ #
431
+ # Invalid BlockdevRef
432
+ #
433
+ iotests.log("=== Invalid BlockdevRef ===")
434
+ iotests.log("")
435
+
436
+ vm.launch()
437
+ blockdev_create(vm, { 'driver': imgfmt,
438
+ 'file': "this doesn't exist",
439
+ 'size': size })
440
+ vm.shutdown()
441
+
442
+ #
443
+ # Zero size
444
+ #
445
+ iotests.log("=== Zero size ===")
446
+ iotests.log("")
447
+
448
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
449
+ vm.launch()
450
+ blockdev_create(vm, { 'driver': imgfmt,
451
+ 'file': 'node0',
452
+ 'size': 0 })
453
+ vm.shutdown()
454
+
455
+ iotests.img_info_log(disk_path)
456
+
457
+ #
458
+ # Maximum size
459
+ #
460
+ iotests.log("=== Maximum size ===")
461
+ iotests.log("")
462
+
463
+ vm.launch()
464
+ blockdev_create(vm, { 'driver': imgfmt,
465
+ 'file': 'node0',
466
+ 'size': 4503599627369984})
467
+ vm.shutdown()
468
+
469
+ iotests.img_info_log(disk_path)
470
+
471
+ #
472
+ # Invalid sizes
473
+ #
474
+
475
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
476
+ # with QAPI's implementation of the 'size' type and affects other commands
477
+ # as well. Once this is fixed, we may want to add a test case here.
478
+
479
+ # 1. Misaligned image size
480
+ # 2. 2^64 - 512
481
+ # 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
482
+ # 4. 2^63 - 512 (generally valid, but with the image header the file will
483
+ # exceed 63 bits)
484
+ # 5. 2^52 (512 bytes more than maximum image size)
485
+
486
+ iotests.log("=== Invalid sizes ===")
487
+ iotests.log("")
488
+
489
+ vm.launch()
490
+ for size in [ 1234, 18446744073709551104, 9223372036854775808,
491
+ 9223372036854775296, 4503599627370497 ]:
492
+ blockdev_create(vm, { 'driver': imgfmt,
493
+ 'file': 'node0',
494
+ 'size': size })
495
+ vm.shutdown()
496
+
497
+ #
498
+ # Invalid cluster size
499
+ #
500
+ iotests.log("=== Invalid cluster size ===")
501
+ iotests.log("")
502
+
503
+ vm.launch()
504
+ for csize in [ 1234, 128, 4294967296, 9223372036854775808,
505
+ 18446744073709551104, 0 ]:
506
+ blockdev_create(vm, { 'driver': imgfmt,
507
+ 'file': 'node0',
508
+ 'size': 67108864,
509
+ 'cluster-size': csize })
510
+ blockdev_create(vm, { 'driver': imgfmt,
511
+ 'file': 'node0',
512
+ 'size': 281474976710656,
513
+ 'cluster-size': 512 })
514
+ vm.shutdown()
515
diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out
516
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
517
--- a/tests/qemu-iotests/212.out
34
--- a/tests/test-bdrv-drain.c
518
+++ b/tests/qemu-iotests/212.out
35
+++ b/tests/test-bdrv-drain.c
519
@@ -XXX,XX +XXX,XX @@
36
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
520
-QA output created by 212
37
do_drain_begin(drain_type, src);
521
-
38
522
=== Successful image creation (defaults) ===
39
if (drain_type == BDRV_DRAIN_ALL) {
523
40
- /* bdrv_drain_all() drains both src and target, and involves an
524
-Testing:
41
- * additional block_job_pause_all() */
525
-QMP_VERSION
42
- g_assert_cmpint(job->pause_count, ==, 3);
526
-{"return": {}}
43
+ /* bdrv_drain_all() drains both src and target */
527
-{"return": {}}
44
+ g_assert_cmpint(job->pause_count, ==, 2);
528
-{"return": {}}
45
} else {
529
-{"return": {}}
46
g_assert_cmpint(job->pause_count, ==, 1);
530
-{"return": {}}
47
}
531
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
48
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
532
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
49
do_drain_begin(drain_type, target);
533
+{u'return': {}}
50
534
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
51
if (drain_type == BDRV_DRAIN_ALL) {
535
+{u'return': {}}
52
- /* bdrv_drain_all() drains both src and target, and involves an
536
+
53
- * additional block_job_pause_all() */
537
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}
54
- g_assert_cmpint(job->pause_count, ==, 3);
538
+{u'return': {}}
55
+ /* bdrv_drain_all() drains both src and target */
539
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'imgfile', 'size': 134217728}}}
56
+ g_assert_cmpint(job->pause_count, ==, 2);
540
+{u'return': {}}
57
} else {
541
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
58
g_assert_cmpint(job->pause_count, ==, 1);
542
+{u'return': {}}
59
}
543
544
-image: TEST_DIR/t.IMGFMT
545
+image: TEST_IMG
546
file format: IMGFMT
547
virtual size: 128M (134217728 bytes)
548
549
=== Successful image creation (explicit defaults) ===
550
551
-Testing:
552
-QMP_VERSION
553
-{"return": {}}
554
-{"return": {}}
555
-{"return": {}}
556
-{"return": {}}
557
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
558
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
559
+{u'return': {}}
560
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
561
+{u'return': {}}
562
563
-image: TEST_DIR/t.IMGFMT
564
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1048576, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 67108864}}}
565
+{u'return': {}}
566
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
567
+{u'return': {}}
568
+
569
+image: TEST_IMG
570
file format: IMGFMT
571
virtual size: 64M (67108864 bytes)
572
573
=== Successful image creation (with non-default options) ===
574
575
-Testing:
576
-QMP_VERSION
577
-{"return": {}}
578
-{"return": {}}
579
-{"return": {}}
580
-{"return": {}}
581
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
582
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
583
+{u'return': {}}
584
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
585
+{u'return': {}}
586
+
587
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 33554432}}}
588
+{u'return': {}}
589
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
590
+{u'return': {}}
591
592
-image: TEST_DIR/t.IMGFMT
593
+image: TEST_IMG
594
file format: IMGFMT
595
virtual size: 32M (33554432 bytes)
596
597
=== Invalid BlockdevRef ===
598
599
-Testing:
600
-QMP_VERSION
601
-{"return": {}}
602
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
603
-{"return": {}}
604
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
605
-
606
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': "this doesn't exist", 'size': 33554432}}}
607
+{u'return': {}}
608
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
609
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
610
+{u'return': {}}
611
612
=== Zero size ===
613
614
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
615
-QMP_VERSION
616
-{"return": {}}
617
-{"return": {}}
618
-{"return": {}}
619
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
620
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 0}}}
621
+{u'return': {}}
622
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
623
+{u'return': {}}
624
625
-image: TEST_DIR/t.IMGFMT
626
+image: TEST_IMG
627
file format: IMGFMT
628
virtual size: 0 (0 bytes)
629
630
=== Maximum size ===
631
632
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
633
-QMP_VERSION
634
-{"return": {}}
635
-{"return": {}}
636
-{"return": {}}
637
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
638
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627369984}}}
639
+{u'return': {}}
640
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
641
+{u'return': {}}
642
643
-image: TEST_DIR/t.IMGFMT
644
+image: TEST_IMG
645
file format: IMGFMT
646
virtual size: 4096T (4503599627369984 bytes)
647
648
=== Invalid sizes ===
649
650
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
651
-QMP_VERSION
652
-{"return": {}}
653
-{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
654
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
655
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
656
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
657
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
658
-{"return": {}}
659
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
660
-
661
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 1234}}}
662
+{u'return': {}}
663
+Job failed: Image size must be a multiple of 512 bytes
664
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
665
+{u'return': {}}
666
+
667
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 18446744073709551104L}}}
668
+{u'return': {}}
669
+Job failed: Image size is too large for this cluster size
670
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
671
+{u'return': {}}
672
+
673
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775808L}}}
674
+{u'return': {}}
675
+Job failed: Image size is too large for this cluster size
676
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
677
+{u'return': {}}
678
+
679
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775296}}}
680
+{u'return': {}}
681
+Job failed: Image size is too large for this cluster size
682
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
683
+{u'return': {}}
684
+
685
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627370497}}}
686
+{u'return': {}}
687
+Job failed: Image size is too large for this cluster size
688
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
689
+{u'return': {}}
690
691
=== Invalid cluster size ===
692
693
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
694
-QMP_VERSION
695
-{"return": {}}
696
-{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}}
697
-{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}}
698
-{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
699
-{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
700
-{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
701
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
702
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
703
-{"return": {}}
704
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
705
-
706
-*** done
707
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
708
+{u'return': {}}
709
+Job failed: Cluster size must be a multiple of 512 bytes
710
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
711
+{u'return': {}}
712
+
713
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
714
+{u'return': {}}
715
+Job failed: Cluster size must be a multiple of 512 bytes
716
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
717
+{u'return': {}}
718
+
719
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4294967296, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
720
+{u'return': {}}
721
+Job failed: Cluster size is too large
722
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
723
+{u'return': {}}
724
+
725
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 9223372036854775808L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
726
+{u'return': {}}
727
+Job failed: Cluster size is too large
728
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
729
+{u'return': {}}
730
+
731
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 18446744073709551104L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
732
+{u'return': {}}
733
+Job failed: Cluster size is too large
734
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
735
+{u'return': {}}
736
+
737
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
738
+{u'return': {}}
739
+Job failed: Image size is too large for this cluster size
740
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
741
+{u'return': {}}
742
+
743
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'parallels', 'file': 'node0', 'size': 281474976710656}}}
744
+{u'return': {}}
745
+Job failed: Image size is too large for this cluster size
746
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
747
+{u'return': {}}
748
+
749
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
750
index XXXXXXX..XXXXXXX 100644
751
--- a/tests/qemu-iotests/group
752
+++ b/tests/qemu-iotests/group
753
@@ -XXX,XX +XXX,XX @@
754
209 rw auto quick
755
210 rw auto
756
211 rw auto quick
757
+212 rw auto quick
758
# TODO The following commented out tests need to be reworked to work
759
# with the x-blockdev-create job
760
-#212 rw auto quick
761
#213 rw auto quick
762
214 rw auto
763
215 rw auto quick
764
--
60
--
765
2.13.6
61
2.13.6
766
62
767
63
diff view generated by jsdifflib
1
This rewrites the test case 211 to work with the new x-blockdev-create
1
bdrv_do_drained_begin() restricts the call of parent callbacks and
2
job rather than the old synchronous version of the command.
2
aio_disable_external() to the outermost drain section, but the block
3
3
driver callbacks are always called. bdrv_do_drained_end() must match
4
All of the test cases stay the same as before, but in order to be able
4
this behaviour, otherwise nodes stay drained even if begin/end calls
5
to implement proper job handling, the test case is rewritten in Python.
5
were balanced.
6
6
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
8
---
10
tests/qemu-iotests/211 | 381 ++++++++++++++++++---------------------------
9
block/io.c | 12 +++++++-----
11
tests/qemu-iotests/211.out | 133 +++++++++-------
10
1 file changed, 7 insertions(+), 5 deletions(-)
12
tests/qemu-iotests/group | 2 +-
13
3 files changed, 229 insertions(+), 287 deletions(-)
14
11
15
diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211
12
diff --git a/block/io.c b/block/io.c
16
index XXXXXXX..XXXXXXX 100755
13
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/211
14
--- a/block/io.c
18
+++ b/tests/qemu-iotests/211
15
+++ b/block/io.c
19
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
20
-#!/bin/bash
17
21
+#!/usr/bin/env python
18
void bdrv_drained_end(BlockDriverState *bs)
22
#
19
{
23
# Test VDI and file image creation
20
+ int old_quiesce_counter;
24
#
25
# Copyright (C) 2018 Red Hat, Inc.
26
#
27
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
28
+#
29
# This program is free software; you can redistribute it and/or modify
30
# it under the terms of the GNU General Public License as published by
31
# the Free Software Foundation; either version 2 of the License, or
32
@@ -XXX,XX +XXX,XX @@
33
# along with this program. If not, see <http://www.gnu.org/licenses/>.
34
#
35
36
-# creator
37
-owner=kwolf@redhat.com
38
-
39
-seq=`basename $0`
40
-echo "QA output created by $seq"
41
-
42
-here=`pwd`
43
-status=1    # failure is the default!
44
-
45
-# get standard environment, filters and checks
46
-. ./common.rc
47
-. ./common.filter
48
-
49
-_supported_fmt vdi
50
-_supported_proto file
51
-_supported_os Linux
52
-
53
-function do_run_qemu()
54
-{
55
- echo Testing: "$@"
56
- $QEMU -nographic -qmp stdio -serial none "$@"
57
- echo
58
-}
59
-
60
-function run_qemu()
61
-{
62
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
63
- | _filter_qemu | _filter_imgfmt \
64
- | _filter_actual_image_size
65
-}
66
-
67
-echo
68
-echo "=== Successful image creation (defaults) ==="
69
-echo
70
-
71
-size=$((128 * 1024 * 1024))
72
-
73
-run_qemu <<EOF
74
-{ "execute": "qmp_capabilities" }
75
-{ "execute": "x-blockdev-create",
76
- "arguments": {
77
- "driver": "file",
78
- "filename": "$TEST_IMG",
79
- "size": 0
80
- }
81
-}
82
-{ "execute": "blockdev-add",
83
- "arguments": {
84
- "driver": "file",
85
- "node-name": "imgfile",
86
- "filename": "$TEST_IMG"
87
- }
88
-}
89
-{ "execute": "x-blockdev-create",
90
- "arguments": {
91
- "driver": "$IMGFMT",
92
- "file": "imgfile",
93
- "size": $size
94
- }
95
-}
96
-{ "execute": "quit" }
97
-EOF
98
-
99
-_img_info --format-specific | _filter_img_info --format-specific
100
-$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
101
-
102
-echo
103
-echo "=== Successful image creation (explicit defaults) ==="
104
-echo
105
-
106
-# Choose a different size to show that we got a new image
107
-size=$((64 * 1024 * 1024))
108
-
109
-run_qemu <<EOF
110
-{ "execute": "qmp_capabilities" }
111
-{ "execute": "x-blockdev-create",
112
- "arguments": {
113
- "driver": "file",
114
- "filename": "$TEST_IMG",
115
- "size": 0
116
- }
117
-}
118
-{ "execute": "x-blockdev-create",
119
- "arguments": {
120
- "driver": "$IMGFMT",
121
- "file": {
122
- "driver": "file",
123
- "filename": "$TEST_IMG"
124
- },
125
- "size": $size,
126
- "preallocation": "off"
127
- }
128
-}
129
-{ "execute": "quit" }
130
-EOF
131
-
132
-_img_info --format-specific | _filter_img_info --format-specific
133
-$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
134
-
135
-echo
136
-echo "=== Successful image creation (with non-default options) ==="
137
-echo
138
-
139
-# Choose a different size to show that we got a new image
140
-size=$((32 * 1024 * 1024))
141
-
142
-run_qemu <<EOF
143
-{ "execute": "qmp_capabilities" }
144
-{ "execute": "x-blockdev-create",
145
- "arguments": {
146
- "driver": "file",
147
- "filename": "$TEST_IMG",
148
- "size": 0
149
- }
150
-}
151
-{ "execute": "x-blockdev-create",
152
- "arguments": {
153
- "driver": "$IMGFMT",
154
- "file": {
155
- "driver": "file",
156
- "filename": "$TEST_IMG"
157
- },
158
- "size": $size,
159
- "preallocation": "metadata"
160
- }
161
-}
162
-{ "execute": "quit" }
163
-EOF
164
-
165
-_img_info --format-specific | _filter_img_info --format-specific
166
-$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
167
-
168
-echo
169
-echo "=== Invalid BlockdevRef ==="
170
-echo
171
-
172
-run_qemu <<EOF
173
-{ "execute": "qmp_capabilities" }
174
-{ "execute": "x-blockdev-create",
175
- "arguments": {
176
- "driver": "$IMGFMT",
177
- "file": "this doesn't exist",
178
- "size": $size
179
- }
180
-}
181
-{ "execute": "quit" }
182
-EOF
183
-
184
-echo
185
-echo "=== Zero size ==="
186
-echo
187
-
188
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
189
-{ "execute": "qmp_capabilities" }
190
-{ "execute": "x-blockdev-create",
191
- "arguments": {
192
- "driver": "$IMGFMT",
193
- "file": "node0",
194
- "size": 0
195
- }
196
-}
197
-{ "execute": "quit" }
198
-EOF
199
-
200
-_img_info | _filter_img_info
201
-
202
-echo
203
-echo "=== Maximum size ==="
204
-echo
205
-
206
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
207
-{ "execute": "qmp_capabilities" }
208
-{ "execute": "x-blockdev-create",
209
- "arguments": {
210
- "driver": "$IMGFMT",
211
- "file": "node0",
212
- "size": 562949819203584
213
- }
214
-}
215
-{ "execute": "quit" }
216
-EOF
217
-
218
-_img_info | _filter_img_info
219
-
220
-echo
221
-echo "=== Invalid sizes ==="
222
-echo
223
-
224
-# TODO Negative image sizes aren't handled correctly, but this is a problem
225
-# with QAPI's implementation of the 'size' type and affects other commands as
226
-# well. Once this is fixed, we may want to add a test case here.
227
-
228
-# 1. 2^64 - 512
229
-# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
230
-# 3. 0x1fffff8000001 (one byte more than maximum image size for VDI)
231
-
232
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
233
-{ "execute": "qmp_capabilities" }
234
-{ "execute": "x-blockdev-create",
235
- "arguments": {
236
- "driver": "$IMGFMT",
237
- "file": "node0",
238
- "size": 18446744073709551104
239
- }
240
-}
241
-{ "execute": "x-blockdev-create",
242
- "arguments": {
243
- "driver": "$IMGFMT",
244
- "file": "node0",
245
- "size": 9223372036854775808
246
- }
247
-}
248
-{ "execute": "x-blockdev-create",
249
- "arguments": {
250
- "driver": "$IMGFMT",
251
- "file": "node0",
252
- "size": 562949819203585
253
- }
254
-}
255
-{ "execute": "quit" }
256
-EOF
257
-
258
-# success, all done
259
-echo "*** done"
260
-rm -f $seq.full
261
-status=0
262
+import iotests
263
+from iotests import imgfmt
264
+
21
+
265
+iotests.verify_image_format(supported_fmts=['vdi'])
22
if (qemu_in_coroutine()) {
266
+iotests.verify_protocol(supported=['file'])
23
bdrv_co_yield_to_drain(bs, false);
267
+
24
return;
268
+def blockdev_create(vm, options):
25
}
269
+ result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
26
assert(bs->quiesce_counter > 0);
270
+
27
- if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
271
+ if 'return' in result:
28
- return;
272
+ assert result['return'] == {}
29
- }
273
+ vm.run_job('job0')
30
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
274
+ iotests.log("")
31
275
+
32
/* Re-enable things in child-to-parent order */
276
+with iotests.FilePath('t.vdi') as disk_path, \
33
bdrv_drain_invoke(bs, false, false);
277
+ iotests.VM() as vm:
34
- bdrv_parent_drained_end(bs);
278
+
35
- aio_enable_external(bdrv_get_aio_context(bs));
279
+ #
36
+ if (old_quiesce_counter == 1) {
280
+ # Successful image creation (defaults)
37
+ bdrv_parent_drained_end(bs);
281
+ #
38
+ aio_enable_external(bdrv_get_aio_context(bs));
282
+ iotests.log("=== Successful image creation (defaults) ===")
39
+ }
283
+ iotests.log("")
40
}
284
+
41
285
+ size = 128 * 1024 * 1024
42
/*
286
+
287
+ vm.launch()
288
+ blockdev_create(vm, { 'driver': 'file',
289
+ 'filename': disk_path,
290
+ 'size': 0 })
291
+
292
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
293
+ node_name='imgfile')
294
+
295
+ blockdev_create(vm, { 'driver': imgfmt,
296
+ 'file': 'imgfile',
297
+ 'size': size })
298
+ vm.shutdown()
299
+
300
+ iotests.img_info_log(disk_path)
301
+ iotests.log(iotests.qemu_img_pipe('map', '--output=json', disk_path))
302
+
303
+ #
304
+ # Successful image creation (explicit defaults)
305
+ #
306
+ iotests.log("=== Successful image creation (explicit defaults) ===")
307
+ iotests.log("")
308
+
309
+ size = 64 * 1024 * 1024
310
+
311
+ vm.launch()
312
+ blockdev_create(vm, { 'driver': 'file',
313
+ 'filename': disk_path,
314
+ 'size': 0 })
315
+ blockdev_create(vm, { 'driver': imgfmt,
316
+ 'file': {
317
+ 'driver': 'file',
318
+ 'filename': disk_path,
319
+ },
320
+ 'size': size,
321
+ 'preallocation': 'off' })
322
+ vm.shutdown()
323
+
324
+ iotests.img_info_log(disk_path)
325
+ iotests.log(iotests.qemu_img_pipe('map', '--output=json', disk_path))
326
+
327
+ #
328
+ # Successful image creation (with non-default options)
329
+ #
330
+ iotests.log("=== Successful image creation (with non-default options) ===")
331
+ iotests.log("")
332
+
333
+ size = 32 * 1024 * 1024
334
+
335
+ vm.launch()
336
+ blockdev_create(vm, { 'driver': 'file',
337
+ 'filename': disk_path,
338
+ 'size': 0 })
339
+ blockdev_create(vm, { 'driver': imgfmt,
340
+ 'file': {
341
+ 'driver': 'file',
342
+ 'filename': disk_path,
343
+ },
344
+ 'size': size,
345
+ 'preallocation': 'metadata' })
346
+ vm.shutdown()
347
+
348
+ iotests.img_info_log(disk_path)
349
+ iotests.log(iotests.qemu_img_pipe('map', '--output=json', disk_path))
350
+
351
+ #
352
+ # Invalid BlockdevRef
353
+ #
354
+ iotests.log("=== Invalid BlockdevRef ===")
355
+ iotests.log("")
356
+
357
+ vm.launch()
358
+ blockdev_create(vm, { 'driver': imgfmt,
359
+ 'file': "this doesn't exist",
360
+ 'size': size })
361
+ vm.shutdown()
362
+
363
+ #
364
+ # Zero size
365
+ #
366
+ iotests.log("=== Zero size ===")
367
+ iotests.log("")
368
+
369
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
370
+ vm.launch()
371
+ blockdev_create(vm, { 'driver': imgfmt,
372
+ 'file': 'node0',
373
+ 'size': 0 })
374
+ vm.shutdown()
375
+
376
+ iotests.img_info_log(disk_path)
377
+
378
+ #
379
+ # Maximum size
380
+ #
381
+ iotests.log("=== Maximum size ===")
382
+ iotests.log("")
383
+
384
+ vm.launch()
385
+ blockdev_create(vm, { 'driver': imgfmt,
386
+ 'file': 'node0',
387
+ 'size': 562949819203584 })
388
+ vm.shutdown()
389
+
390
+ iotests.img_info_log(disk_path)
391
+
392
+ #
393
+ # Invalid sizes
394
+ #
395
+
396
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
397
+ # with QAPI's implementation of the 'size' type and affects other commands
398
+ # as well. Once this is fixed, we may want to add a test case here.
399
+
400
+ # 1. 2^64 - 512
401
+ # 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
402
+ # 3. 0x1fffff8000001 (one byte more than maximum image size for VDI)
403
+
404
+ iotests.log("=== Invalid sizes ===")
405
+ iotests.log("")
406
+
407
+ vm.launch()
408
+ for size in [ 18446744073709551104, 9223372036854775808, 562949819203585 ]:
409
+ blockdev_create(vm, { 'driver': imgfmt,
410
+ 'file': 'node0',
411
+ 'size': size })
412
+ vm.shutdown()
413
diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out
414
index XXXXXXX..XXXXXXX 100644
415
--- a/tests/qemu-iotests/211.out
416
+++ b/tests/qemu-iotests/211.out
417
@@ -XXX,XX +XXX,XX @@
418
-QA output created by 211
419
-
420
=== Successful image creation (defaults) ===
421
422
-Testing:
423
-QMP_VERSION
424
-{"return": {}}
425
-{"return": {}}
426
-{"return": {}}
427
-{"return": {}}
428
-{"return": {}}
429
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
430
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
431
+{u'return': {}}
432
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
433
+{u'return': {}}
434
+
435
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}
436
+{u'return': {}}
437
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'imgfile', 'size': 134217728}}}
438
+{u'return': {}}
439
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
440
+{u'return': {}}
441
442
-image: TEST_DIR/t.IMGFMT
443
+image: TEST_IMG
444
file format: IMGFMT
445
virtual size: 128M (134217728 bytes)
446
+cluster_size: 1048576
447
+
448
[{ "start": 0, "length": 134217728, "depth": 0, "zero": true, "data": false}]
449
450
=== Successful image creation (explicit defaults) ===
451
452
-Testing:
453
-QMP_VERSION
454
-{"return": {}}
455
-{"return": {}}
456
-{"return": {}}
457
-{"return": {}}
458
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
459
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
460
+{u'return': {}}
461
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
462
+{u'return': {}}
463
464
-image: TEST_DIR/t.IMGFMT
465
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'off', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 67108864}}}
466
+{u'return': {}}
467
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
468
+{u'return': {}}
469
+
470
+image: TEST_IMG
471
file format: IMGFMT
472
virtual size: 64M (67108864 bytes)
473
+cluster_size: 1048576
474
+
475
[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}]
476
477
=== Successful image creation (with non-default options) ===
478
479
-Testing:
480
-QMP_VERSION
481
-{"return": {}}
482
-{"return": {}}
483
-{"return": {}}
484
-{"return": {}}
485
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
486
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
487
+{u'return': {}}
488
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
489
+{u'return': {}}
490
491
-image: TEST_DIR/t.IMGFMT
492
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'metadata', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 33554432}}}
493
+{u'return': {}}
494
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
495
+{u'return': {}}
496
+
497
+image: TEST_IMG
498
file format: IMGFMT
499
virtual size: 32M (33554432 bytes)
500
-[{ "start": 0, "length": 3072, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
501
-{ "start": 3072, "length": 33551360, "depth": 0, "zero": true, "data": true, "offset": OFFSET}]
502
+cluster_size: 1048576
503
504
-=== Invalid BlockdevRef ===
505
+[{ "start": 0, "length": 3072, "depth": 0, "zero": false, "data": true, "offset": 1024},
506
+{ "start": 3072, "length": 33551360, "depth": 0, "zero": true, "data": true, "offset": 4096}]
507
508
-Testing:
509
-QMP_VERSION
510
-{"return": {}}
511
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
512
-{"return": {}}
513
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
514
+=== Invalid BlockdevRef ===
515
516
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': "this doesn't exist", 'size': 33554432}}}
517
+{u'return': {}}
518
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
519
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
520
+{u'return': {}}
521
522
=== Zero size ===
523
524
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
525
-QMP_VERSION
526
-{"return": {}}
527
-{"return": {}}
528
-{"return": {}}
529
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
530
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 0}}}
531
+{u'return': {}}
532
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
533
+{u'return': {}}
534
535
-image: TEST_DIR/t.IMGFMT
536
+image: TEST_IMG
537
file format: IMGFMT
538
virtual size: 0 (0 bytes)
539
+cluster_size: 1048576
540
541
=== Maximum size ===
542
543
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
544
-QMP_VERSION
545
-{"return": {}}
546
-{"return": {}}
547
-{"return": {}}
548
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
549
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203584}}}
550
+{u'return': {}}
551
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
552
+{u'return': {}}
553
554
-image: TEST_DIR/t.IMGFMT
555
+image: TEST_IMG
556
file format: IMGFMT
557
virtual size: 512T (562949819203584 bytes)
558
+cluster_size: 1048576
559
560
=== Invalid sizes ===
561
562
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
563
-QMP_VERSION
564
-{"return": {}}
565
-{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)"}}
566
-{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)"}}
567
-{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)"}}
568
-{"return": {}}
569
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
570
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 18446744073709551104L}}}
571
+{u'return': {}}
572
+Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)
573
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
574
+{u'return': {}}
575
+
576
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 9223372036854775808L}}}
577
+{u'return': {}}
578
+Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)
579
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
580
+{u'return': {}}
581
+
582
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203585}}}
583
+{u'return': {}}
584
+Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)
585
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
586
+{u'return': {}}
587
588
-*** done
589
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
590
index XXXXXXX..XXXXXXX 100644
591
--- a/tests/qemu-iotests/group
592
+++ b/tests/qemu-iotests/group
593
@@ -XXX,XX +XXX,XX @@
594
208 rw auto quick
595
209 rw auto quick
596
210 rw auto
597
+211 rw auto quick
598
# TODO The following commented out tests need to be reworked to work
599
# with the x-blockdev-create job
600
-#211 rw auto quick
601
#212 rw auto quick
602
#213 rw auto quick
603
214 rw auto
604
--
43
--
605
2.13.6
44
2.13.6
606
45
607
46
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
3
tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
4
1 file changed, 57 insertions(+)
1
5
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
7
index XXXXXXX..XXXXXXX 100644
8
--- a/tests/test-bdrv-drain.c
9
+++ b/tests/test-bdrv-drain.c
10
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
11
enum drain_type {
12
BDRV_DRAIN_ALL,
13
BDRV_DRAIN,
14
+ DRAIN_TYPE_MAX,
15
};
16
17
static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
18
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
19
test_quiesce_common(BDRV_DRAIN, false);
20
}
21
22
+static void test_nested(void)
23
+{
24
+ BlockBackend *blk;
25
+ BlockDriverState *bs, *backing;
26
+ BDRVTestState *s, *backing_s;
27
+ enum drain_type outer, inner;
28
+
29
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
30
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
31
+ &error_abort);
32
+ s = bs->opaque;
33
+ blk_insert_bs(blk, bs, &error_abort);
34
+
35
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
36
+ backing_s = backing->opaque;
37
+ bdrv_set_backing_hd(bs, backing, &error_abort);
38
+
39
+ for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
40
+ for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
41
+ /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
42
+ int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
43
+ (inner != BDRV_DRAIN_ALL);
44
+ int backing_quiesce = 0;
45
+ int backing_cb_cnt = (outer != BDRV_DRAIN) +
46
+ (inner != BDRV_DRAIN);
47
+
48
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
49
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
50
+ g_assert_cmpint(s->drain_count, ==, 0);
51
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
52
+
53
+ do_drain_begin(outer, bs);
54
+ do_drain_begin(inner, bs);
55
+
56
+ g_assert_cmpint(bs->quiesce_counter, ==, bs_quiesce);
57
+ g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce);
58
+ g_assert_cmpint(s->drain_count, ==, 2);
59
+ g_assert_cmpint(backing_s->drain_count, ==, backing_cb_cnt);
60
+
61
+ do_drain_end(inner, bs);
62
+ do_drain_end(outer, bs);
63
+
64
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
65
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
66
+ g_assert_cmpint(s->drain_count, ==, 0);
67
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
68
+ }
69
+ }
70
+
71
+ bdrv_unref(backing);
72
+ bdrv_unref(bs);
73
+ blk_unref(blk);
74
+}
75
+
76
77
typedef struct TestBlockJob {
78
BlockJob common;
79
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
80
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
81
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
82
83
+ g_test_add_func("/bdrv-drain/nested", test_nested);
84
+
85
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
86
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
87
88
--
89
2.13.6
90
91
diff view generated by jsdifflib
1
This rewrites the test case 210 to work with the new x-blockdev-create
1
This is in preparation for subtree drains, i.e. drained sections that
2
job rather than the old synchronous version of the command.
2
affect not only a single node, but recursively all child nodes, too.
3
3
4
All of the test cases stay the same as before, but in order to be able
4
Calling the parent callbacks for drain is pointless when we just came
5
to implement proper job handling, the test case is rewritten in Python.
5
from that parent node recursively and leads to multiple increases of
6
bs->quiesce_counter in a single drain call. Don't do it.
7
8
In order for this to work correctly, the parent callback must be called
9
for every bdrv_drain_begin/end() call, not only for the outermost one:
10
11
If we have a node N with two parents A and B, recursive draining of A
12
should cause the quiesce_counter of B to increase because its child N is
13
drained independently of B. If now B is recursively drained, too, A must
14
increase its quiesce_counter because N is drained independently of A
15
only now, even if N is going from quiesce_counter 1 to 2.
6
16
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
---
18
---
11
tests/qemu-iotests/210 | 393 ++++++++++++++++++------------------------
19
include/block/block.h | 4 ++--
12
tests/qemu-iotests/210.out | 197 ++++++++++++++-------
20
block.c | 13 +++++++++----
13
tests/qemu-iotests/group | 2 +-
21
block/io.c | 47 ++++++++++++++++++++++++++++++++++-------------
14
tests/qemu-iotests/iotests.py | 12 +-
22
3 files changed, 45 insertions(+), 19 deletions(-)
15
4 files changed, 314 insertions(+), 290 deletions(-)
23
16
24
diff --git a/include/block/block.h b/include/block/block.h
17
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
25
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100755
26
--- a/include/block/block.h
19
--- a/tests/qemu-iotests/210
27
+++ b/include/block/block.h
20
+++ b/tests/qemu-iotests/210
28
@@ -XXX,XX +XXX,XX @@ void bdrv_io_unplug(BlockDriverState *bs);
29
* Begin a quiesced section of all users of @bs. This is part of
30
* bdrv_drained_begin.
31
*/
32
-void bdrv_parent_drained_begin(BlockDriverState *bs);
33
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore);
34
35
/**
36
* bdrv_parent_drained_end:
37
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin(BlockDriverState *bs);
38
* End a quiesced section of all users of @bs. This is part of
39
* bdrv_drained_end.
40
*/
41
-void bdrv_parent_drained_end(BlockDriverState *bs);
42
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
43
44
/**
45
* bdrv_drained_begin:
46
diff --git a/block.c b/block.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block.c
49
+++ b/block.c
50
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
51
BlockDriverState *new_bs)
52
{
53
BlockDriverState *old_bs = child->bs;
54
+ int i;
55
56
if (old_bs && new_bs) {
57
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
58
}
59
if (old_bs) {
60
if (old_bs->quiesce_counter && child->role->drained_end) {
61
- child->role->drained_end(child);
62
+ for (i = 0; i < old_bs->quiesce_counter; i++) {
63
+ child->role->drained_end(child);
64
+ }
65
}
66
if (child->role->detach) {
67
child->role->detach(child);
68
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
69
if (new_bs) {
70
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
71
if (new_bs->quiesce_counter && child->role->drained_begin) {
72
- child->role->drained_begin(child);
73
+ for (i = 0; i < new_bs->quiesce_counter; i++) {
74
+ child->role->drained_begin(child);
75
+ }
76
}
77
78
if (child->role->attach) {
79
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
80
AioContext *ctx = bdrv_get_aio_context(bs);
81
82
aio_disable_external(ctx);
83
- bdrv_parent_drained_begin(bs);
84
+ bdrv_parent_drained_begin(bs, NULL);
85
bdrv_drain(bs); /* ensure there are no in-flight requests */
86
87
while (aio_poll(ctx, false)) {
88
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
89
*/
90
aio_context_acquire(new_context);
91
bdrv_attach_aio_context(bs, new_context);
92
- bdrv_parent_drained_end(bs);
93
+ bdrv_parent_drained_end(bs, NULL);
94
aio_enable_external(ctx);
95
aio_context_release(new_context);
96
}
97
diff --git a/block/io.c b/block/io.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/io.c
100
+++ b/block/io.c
21
@@ -XXX,XX +XXX,XX @@
101
@@ -XXX,XX +XXX,XX @@
22
-#!/bin/bash
102
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
23
+#!/usr/bin/env python
103
int64_t offset, int bytes, BdrvRequestFlags flags);
24
#
104
25
# Test luks and file image creation
105
-void bdrv_parent_drained_begin(BlockDriverState *bs)
26
#
106
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
27
# Copyright (C) 2018 Red Hat, Inc.
107
{
28
#
108
BdrvChild *c, *next;
29
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
109
30
+#
110
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
31
# This program is free software; you can redistribute it and/or modify
111
+ if (c == ignore) {
32
# it under the terms of the GNU General Public License as published by
112
+ continue;
33
# the Free Software Foundation; either version 2 of the License, or
113
+ }
34
@@ -XXX,XX +XXX,XX @@
114
if (c->role->drained_begin) {
35
# along with this program. If not, see <http://www.gnu.org/licenses/>.
115
c->role->drained_begin(c);
36
#
116
}
37
117
}
38
-# creator
118
}
39
-owner=kwolf@redhat.com
119
40
-
120
-void bdrv_parent_drained_end(BlockDriverState *bs)
41
-seq=`basename $0`
121
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
42
-echo "QA output created by $seq"
122
{
43
-
123
BdrvChild *c, *next;
44
-here=`pwd`
124
45
-status=1    # failure is the default!
125
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
46
-
126
+ if (c == ignore) {
47
-# get standard environment, filters and checks
127
+ continue;
48
-. ./common.rc
128
+ }
49
-. ./common.filter
129
if (c->role->drained_end) {
50
-
130
c->role->drained_end(c);
51
-_supported_fmt luks
131
}
52
-_supported_proto file
132
@@ -XXX,XX +XXX,XX @@ typedef struct {
53
-_supported_os Linux
133
BlockDriverState *bs;
54
-
134
bool done;
55
-function do_run_qemu()
135
bool begin;
56
-{
136
+ BdrvChild *parent;
57
- echo Testing: "$@"
137
} BdrvCoDrainData;
58
- $QEMU -nographic -qmp stdio -serial none "$@"
138
59
- echo
139
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
60
-}
140
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
61
-
141
return waited;
62
-function run_qemu()
142
}
63
-{
143
64
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
144
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
65
- | _filter_qemu | _filter_imgfmt \
145
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
66
- | _filter_actual_image_size
67
-}
68
-
69
-echo
70
-echo "=== Successful image creation (defaults) ==="
71
-echo
72
-
73
-size=$((128 * 1024 * 1024))
74
-
75
-run_qemu -object secret,id=keysec0,data="foo" <<EOF
76
-{ "execute": "qmp_capabilities" }
77
-{ "execute": "x-blockdev-create",
78
- "arguments": {
79
- "driver": "file",
80
- "filename": "$TEST_IMG_FILE",
81
- "size": 0
82
- }
83
-}
84
-{ "execute": "blockdev-add",
85
- "arguments": {
86
- "driver": "file",
87
- "node-name": "imgfile",
88
- "filename": "$TEST_IMG_FILE"
89
- }
90
-}
91
-{ "execute": "x-blockdev-create",
92
- "arguments": {
93
- "driver": "$IMGFMT",
94
- "file": "imgfile",
95
- "key-secret": "keysec0",
96
- "size": $size,
97
- "iter-time": 10
98
- }
99
-}
100
-{ "execute": "quit" }
101
-EOF
102
-
103
-_img_info --format-specific | _filter_img_info --format-specific
104
-
105
-echo
106
-echo "=== Successful image creation (with non-default options) ==="
107
-echo
108
-
109
-# Choose a different size to show that we got a new image
110
-size=$((64 * 1024 * 1024))
111
-
112
-run_qemu -object secret,id=keysec0,data="foo" <<EOF
113
-{ "execute": "qmp_capabilities" }
114
-{ "execute": "x-blockdev-create",
115
- "arguments": {
116
- "driver": "file",
117
- "filename": "$TEST_IMG_FILE",
118
- "size": 0
119
- }
120
-}
121
-{ "execute": "x-blockdev-create",
122
- "arguments": {
123
- "driver": "$IMGFMT",
124
- "file": {
125
- "driver": "file",
126
- "filename": "$TEST_IMG_FILE"
127
- },
128
- "size": $size,
129
- "key-secret": "keysec0",
130
- "cipher-alg": "twofish-128",
131
- "cipher-mode": "ctr",
132
- "ivgen-alg": "plain64",
133
- "ivgen-hash-alg": "md5",
134
- "hash-alg": "sha1",
135
- "iter-time": 10
136
- }
137
-}
138
-{ "execute": "quit" }
139
-EOF
140
-
141
-_img_info --format-specific | _filter_img_info --format-specific
142
-
143
-echo
144
-echo "=== Invalid BlockdevRef ==="
145
-echo
146
-
147
-run_qemu <<EOF
148
-{ "execute": "qmp_capabilities" }
149
-{ "execute": "x-blockdev-create",
150
- "arguments": {
151
- "driver": "$IMGFMT",
152
- "file": "this doesn't exist",
153
- "size": $size
154
- }
155
-}
156
-{ "execute": "quit" }
157
-EOF
158
-
159
-echo
160
-echo "=== Zero size ==="
161
-echo
162
-
163
-run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
164
- -object secret,id=keysec0,data="foo" <<EOF
165
-{ "execute": "qmp_capabilities" }
166
-{ "execute": "x-blockdev-create",
167
- "arguments": {
168
- "driver": "$IMGFMT",
169
- "file": "node0",
170
- "key-secret": "keysec0",
171
- "size": 0,
172
- "iter-time": 10
173
- }
174
-}
175
-{ "execute": "quit" }
176
-EOF
177
-
178
-_img_info | _filter_img_info
179
-
180
-
181
-echo
182
-echo "=== Invalid sizes ==="
183
-echo
184
-
185
-# TODO Negative image sizes aren't handled correctly, but this is a problem
186
-# with QAPI's implementation of the 'size' type and affects other commands as
187
-# well. Once this is fixed, we may want to add a test case here.
188
-
189
-# 1. 2^64 - 512
190
-# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
191
-# 3. 2^63 - 512 (generally valid, but with the crypto header the file will
192
-# exceed 63 bits)
193
-
194
-run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
195
- -object secret,id=keysec0,data="foo" <<EOF
196
-{ "execute": "qmp_capabilities" }
197
-{ "execute": "x-blockdev-create",
198
- "arguments": {
199
- "driver": "$IMGFMT",
200
- "file": "node0",
201
- "key-secret": "keysec0",
202
- "size": 18446744073709551104
203
- }
204
-}
205
-{ "execute": "x-blockdev-create",
206
- "arguments": {
207
- "driver": "$IMGFMT",
208
- "file": "node0",
209
- "key-secret": "keysec0",
210
- "size": 9223372036854775808
211
- }
212
-}
213
-{ "execute": "x-blockdev-create",
214
- "arguments": {
215
- "driver": "$IMGFMT",
216
- "file": "node0",
217
- "key-secret": "keysec0",
218
- "size": 9223372036854775296
219
- }
220
-}
221
-{ "execute": "quit" }
222
-EOF
223
-
224
-echo
225
-echo "=== Resize image with invalid sizes ==="
226
-echo
227
-
228
-run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
229
- -blockdev driver=luks,file=node0,key-secret=keysec0,node-name=node1 \
230
- -object secret,id=keysec0,data="foo" <<EOF
231
-{ "execute": "qmp_capabilities" }
232
-{ "execute": "block_resize",
233
- "arguments": {
234
- "node-name": "node1",
235
- "size": 9223372036854775296
236
- }
237
-}
238
-{ "execute": "block_resize",
239
- "arguments": {
240
- "node-name": "node1",
241
- "size": 9223372036854775808
242
- }
243
-}
244
-{ "execute": "block_resize",
245
- "arguments": {
246
- "node-name": "node1",
247
- "size": 18446744073709551104
248
- }
249
-}
250
-{ "execute": "block_resize",
251
- "arguments": {
252
- "node-name": "node1",
253
- "size": -9223372036854775808
254
- }
255
-}
256
-{ "execute": "quit" }
257
-EOF
258
-
259
-_img_info | _filter_img_info
260
-
261
-# success, all done
262
-echo "*** done"
263
-rm -f $seq.full
264
-status=0
265
+import iotests
266
+from iotests import imgfmt
267
+
146
+
268
+iotests.verify_image_format(supported_fmts=['luks'])
147
static void bdrv_co_drain_bh_cb(void *opaque)
269
+iotests.verify_protocol(supported=['file'])
148
{
149
BdrvCoDrainData *data = opaque;
150
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
151
152
bdrv_dec_in_flight(bs);
153
if (data->begin) {
154
- bdrv_drained_begin(bs);
155
+ bdrv_do_drained_begin(bs, data->parent);
156
} else {
157
- bdrv_drained_end(bs);
158
+ bdrv_do_drained_end(bs, data->parent);
159
}
160
161
data->done = true;
162
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
163
}
164
165
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
166
- bool begin)
167
+ bool begin, BdrvChild *parent)
168
{
169
BdrvCoDrainData data;
170
171
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
172
.bs = bs,
173
.done = false,
174
.begin = begin,
175
+ .parent = parent,
176
};
177
bdrv_inc_in_flight(bs);
178
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
179
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
180
assert(data.done);
181
}
182
183
-void bdrv_drained_begin(BlockDriverState *bs)
184
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
185
{
186
if (qemu_in_coroutine()) {
187
- bdrv_co_yield_to_drain(bs, true);
188
+ bdrv_co_yield_to_drain(bs, true, parent);
189
return;
190
}
191
192
/* Stop things in parent-to-child order */
193
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
194
aio_disable_external(bdrv_get_aio_context(bs));
195
- bdrv_parent_drained_begin(bs);
196
}
197
198
+ bdrv_parent_drained_begin(bs, parent);
199
bdrv_drain_invoke(bs, true, false);
200
bdrv_drain_recurse(bs);
201
}
202
203
-void bdrv_drained_end(BlockDriverState *bs)
204
+void bdrv_drained_begin(BlockDriverState *bs)
205
+{
206
+ bdrv_do_drained_begin(bs, NULL);
207
+}
270
+
208
+
271
+def blockdev_create(vm, options):
209
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
272
+ result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
210
{
211
int old_quiesce_counter;
212
213
if (qemu_in_coroutine()) {
214
- bdrv_co_yield_to_drain(bs, false);
215
+ bdrv_co_yield_to_drain(bs, false, parent);
216
return;
217
}
218
assert(bs->quiesce_counter > 0);
219
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
220
221
/* Re-enable things in child-to-parent order */
222
bdrv_drain_invoke(bs, false, false);
223
+ bdrv_parent_drained_end(bs, parent);
224
if (old_quiesce_counter == 1) {
225
- bdrv_parent_drained_end(bs);
226
aio_enable_external(bdrv_get_aio_context(bs));
227
}
228
}
229
230
+void bdrv_drained_end(BlockDriverState *bs)
231
+{
232
+ bdrv_do_drained_end(bs, NULL);
233
+}
273
+
234
+
274
+ if 'return' in result:
235
/*
275
+ assert result['return'] == {}
236
* Wait for pending requests to complete on a single BlockDriverState subtree,
276
+ vm.run_job('job0')
237
* and suspend block driver's internal I/O until next request arrives.
277
+ iotests.log("")
238
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
278
+
239
/* Stop things in parent-to-child order */
279
+with iotests.FilePath('t.luks') as disk_path, \
240
aio_context_acquire(aio_context);
280
+ iotests.VM() as vm:
241
aio_disable_external(aio_context);
281
+
242
- bdrv_parent_drained_begin(bs);
282
+ vm.add_object('secret,id=keysec0,data=foo')
243
+ bdrv_parent_drained_begin(bs, NULL);
283
+
244
bdrv_drain_invoke(bs, true, true);
284
+ #
245
aio_context_release(aio_context);
285
+ # Successful image creation (defaults)
246
286
+ #
247
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
287
+ iotests.log("=== Successful image creation (defaults) ===")
248
/* Re-enable things in child-to-parent order */
288
+ iotests.log("")
249
aio_context_acquire(aio_context);
289
+
250
bdrv_drain_invoke(bs, false, true);
290
+ size = 128 * 1024 * 1024
251
- bdrv_parent_drained_end(bs);
291
+
252
+ bdrv_parent_drained_end(bs, NULL);
292
+ vm.launch()
253
aio_enable_external(aio_context);
293
+ blockdev_create(vm, { 'driver': 'file',
254
aio_context_release(aio_context);
294
+ 'filename': disk_path,
255
}
295
+ 'size': 0 })
296
+
297
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
298
+ node_name='imgfile')
299
+
300
+ blockdev_create(vm, { 'driver': imgfmt,
301
+ 'file': 'imgfile',
302
+ 'key-secret': 'keysec0',
303
+ 'size': size,
304
+ 'iter-time': 10 })
305
+ vm.shutdown()
306
+
307
+ # TODO Proper support for images to be used with imgopts and/or protocols
308
+ iotests.img_info_log(
309
+ 'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
310
+ filter_path=disk_path,
311
+ extra_args=['--object', 'secret,id=keysec0,data=foo'],
312
+ imgopts=True)
313
+
314
+ #
315
+ # Successful image creation (with non-default options)
316
+ #
317
+ iotests.log("=== Successful image creation (with non-default options) ===")
318
+ iotests.log("")
319
+
320
+ size = 64 * 1024 * 1024
321
+
322
+ vm.launch()
323
+ blockdev_create(vm, { 'driver': 'file',
324
+ 'filename': disk_path,
325
+ 'size': 0 })
326
+ blockdev_create(vm, { 'driver': imgfmt,
327
+ 'file': {
328
+ 'driver': 'file',
329
+ 'filename': disk_path,
330
+ },
331
+ 'size': size,
332
+ 'key-secret': 'keysec0',
333
+ 'cipher-alg': 'twofish-128',
334
+ 'cipher-mode': 'ctr',
335
+ 'ivgen-alg': 'plain64',
336
+ 'ivgen-hash-alg': 'md5',
337
+ 'hash-alg': 'sha1',
338
+ 'iter-time': 10 })
339
+ vm.shutdown()
340
+
341
+ # TODO Proper support for images to be used with imgopts and/or protocols
342
+ iotests.img_info_log(
343
+ 'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
344
+ filter_path=disk_path,
345
+ extra_args=['--object', 'secret,id=keysec0,data=foo'],
346
+ imgopts=True)
347
+
348
+ #
349
+ # Invalid BlockdevRef
350
+ #
351
+ iotests.log("=== Invalid BlockdevRef ===")
352
+ iotests.log("")
353
+
354
+ size = 64 * 1024 * 1024
355
+
356
+ vm.launch()
357
+ blockdev_create(vm, { 'driver': imgfmt,
358
+ 'file': "this doesn't exist",
359
+ 'size': size })
360
+ vm.shutdown()
361
+
362
+ #
363
+ # Zero size
364
+ #
365
+ iotests.log("=== Zero size ===")
366
+ iotests.log("")
367
+
368
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
369
+ vm.launch()
370
+ blockdev_create(vm, { 'driver': imgfmt,
371
+ 'file': 'node0',
372
+ 'key-secret': 'keysec0',
373
+ 'size': 0,
374
+ 'iter-time': 10 })
375
+ vm.shutdown()
376
+
377
+ # TODO Proper support for images to be used with imgopts and/or protocols
378
+ iotests.img_info_log(
379
+ 'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
380
+ filter_path=disk_path,
381
+ extra_args=['--object', 'secret,id=keysec0,data=foo'],
382
+ imgopts=True)
383
+
384
+ #
385
+ # Invalid sizes
386
+ #
387
+
388
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
389
+ # with QAPI's implementation of the 'size' type and affects other commands as
390
+ # well. Once this is fixed, we may want to add a test case here.
391
+
392
+ # 1. 2^64 - 512
393
+ # 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
394
+ # 3. 2^63 - 512 (generally valid, but with the crypto header the file will
395
+ # exceed 63 bits)
396
+ iotests.log("=== Invalid sizes ===")
397
+ iotests.log("")
398
+
399
+ vm.launch()
400
+ for size in [ 18446744073709551104, 9223372036854775808, 9223372036854775296 ]:
401
+ blockdev_create(vm, { 'driver': imgfmt,
402
+ 'file': 'node0',
403
+ 'key-secret': 'keysec0',
404
+ 'size': size })
405
+ vm.shutdown()
406
+
407
+ #
408
+ # Resize image with invalid sizes
409
+ #
410
+ iotests.log("=== Resize image with invalid sizes ===")
411
+ iotests.log("")
412
+
413
+ vm.add_blockdev('driver=luks,file=node0,key-secret=keysec0,node-name=node1')
414
+ vm.launch()
415
+ vm.qmp_log('block_resize', node_name='node1', size=9223372036854775296)
416
+ vm.qmp_log('block_resize', node_name='node1', size=9223372036854775808)
417
+ vm.qmp_log('block_resize', node_name='node1', size=18446744073709551104)
418
+ vm.qmp_log('block_resize', node_name='node1', size=-9223372036854775808)
419
+ vm.shutdown()
420
+
421
+ # TODO Proper support for images to be used with imgopts and/or protocols
422
+ iotests.img_info_log(
423
+ 'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
424
+ filter_path=disk_path,
425
+ extra_args=['--object', 'secret,id=keysec0,data=foo'],
426
+ imgopts=True)
427
diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out
428
index XXXXXXX..XXXXXXX 100644
429
--- a/tests/qemu-iotests/210.out
430
+++ b/tests/qemu-iotests/210.out
431
@@ -XXX,XX +XXX,XX @@
432
-QA output created by 210
433
-
434
=== Successful image creation (defaults) ===
435
436
-Testing: -object secret,id=keysec0,data=foo
437
-QMP_VERSION
438
-{"return": {}}
439
-{"return": {}}
440
-{"return": {}}
441
-{"return": {}}
442
-{"return": {}}
443
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
444
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}}
445
+{u'return': {}}
446
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
447
+{u'return': {}}
448
+
449
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}
450
+{u'return': {}}
451
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'imgfile', 'size': 134217728}}}
452
+{u'return': {}}
453
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
454
+{u'return': {}}
455
456
-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
457
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
458
file format: IMGFMT
459
virtual size: 128M (134217728 bytes)
460
+encrypted: yes
461
Format specific information:
462
ivgen alg: plain64
463
hash alg: sha256
464
cipher alg: aes-256
465
- uuid: 00000000-0000-0000-0000-000000000000
466
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
467
cipher mode: xts
468
slots:
469
[0]:
470
active: true
471
- iters: 1024
472
+ iters: XXX
473
key offset: 4096
474
stripes: 4000
475
[1]:
476
@@ -XXX,XX +XXX,XX @@ Format specific information:
477
active: false
478
key offset: 1810432
479
payload offset: 2068480
480
- master key iters: 1024
481
+ master key iters: XXX
482
483
=== Successful image creation (with non-default options) ===
484
485
-Testing: -object secret,id=keysec0,data=foo
486
-QMP_VERSION
487
-{"return": {}}
488
-{"return": {}}
489
-{"return": {}}
490
-{"return": {}}
491
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
492
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}}
493
+{u'return': {}}
494
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
495
+{u'return': {}}
496
+
497
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'hash-alg': 'sha1', 'cipher-mode': 'ctr', 'cipher-alg': 'twofish-128', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}, 'iter-time': 10, 'ivgen-alg': 'plain64', 'ivgen-hash-alg': 'md5', 'driver': 'luks', 'size': 67108864}}}
498
+{u'return': {}}
499
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
500
+{u'return': {}}
501
502
-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
503
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
504
file format: IMGFMT
505
virtual size: 64M (67108864 bytes)
506
+encrypted: yes
507
Format specific information:
508
ivgen alg: plain64
509
hash alg: sha1
510
cipher alg: twofish-128
511
- uuid: 00000000-0000-0000-0000-000000000000
512
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
513
cipher mode: ctr
514
slots:
515
[0]:
516
active: true
517
- iters: 1024
518
+ iters: XXX
519
key offset: 4096
520
stripes: 4000
521
[1]:
522
@@ -XXX,XX +XXX,XX @@ Format specific information:
523
active: false
524
key offset: 462848
525
payload offset: 528384
526
- master key iters: 1024
527
+ master key iters: XXX
528
529
=== Invalid BlockdevRef ===
530
531
-Testing:
532
-QMP_VERSION
533
-{"return": {}}
534
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
535
-{"return": {}}
536
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
537
-
538
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'luks', 'file': "this doesn't exist", 'size': 67108864}}}
539
+{u'return': {}}
540
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
541
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
542
+{u'return': {}}
543
544
=== Zero size ===
545
546
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -object secret,id=keysec0,data=foo
547
-QMP_VERSION
548
-{"return": {}}
549
-{"return": {}}
550
-{"return": {}}
551
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
552
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'node0', 'size': 0}}}
553
+{u'return': {}}
554
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
555
+{u'return': {}}
556
557
-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
558
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
559
file format: IMGFMT
560
virtual size: 0 (0 bytes)
561
+encrypted: yes
562
+Format specific information:
563
+ ivgen alg: plain64
564
+ hash alg: sha256
565
+ cipher alg: aes-256
566
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
567
+ cipher mode: xts
568
+ slots:
569
+ [0]:
570
+ active: true
571
+ iters: XXX
572
+ key offset: 4096
573
+ stripes: 4000
574
+ [1]:
575
+ active: false
576
+ key offset: 262144
577
+ [2]:
578
+ active: false
579
+ key offset: 520192
580
+ [3]:
581
+ active: false
582
+ key offset: 778240
583
+ [4]:
584
+ active: false
585
+ key offset: 1036288
586
+ [5]:
587
+ active: false
588
+ key offset: 1294336
589
+ [6]:
590
+ active: false
591
+ key offset: 1552384
592
+ [7]:
593
+ active: false
594
+ key offset: 1810432
595
+ payload offset: 2068480
596
+ master key iters: XXX
597
598
=== Invalid sizes ===
599
600
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -object secret,id=keysec0,data=foo
601
-QMP_VERSION
602
-{"return": {}}
603
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
604
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
605
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
606
-{"return": {}}
607
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
608
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 18446744073709551104L}}}
609
+{u'return': {}}
610
+Job failed: The requested file size is too large
611
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
612
+{u'return': {}}
613
+
614
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775808L}}}
615
+{u'return': {}}
616
+Job failed: The requested file size is too large
617
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
618
+{u'return': {}}
619
620
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775296}}}
621
+{u'return': {}}
622
+Job failed: The requested file size is too large
623
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
624
+{u'return': {}}
625
626
=== Resize image with invalid sizes ===
627
628
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -blockdev driver=IMGFMT,file=node0,key-secret=keysec0,node-name=node1 -object secret,id=keysec0,data=foo
629
-QMP_VERSION
630
-{"return": {}}
631
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
632
-{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
633
-{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
634
-{"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}}
635
-{"return": {}}
636
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
637
-
638
-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
639
+{'execute': 'block_resize', 'arguments': {'size': 9223372036854775296, 'node_name': 'node1'}}
640
+{u'error': {u'class': u'GenericError', u'desc': u'The requested file size is too large'}}
641
+{'execute': 'block_resize', 'arguments': {'size': 9223372036854775808L, 'node_name': 'node1'}}
642
+{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter type for 'size', expected: integer"}}
643
+{'execute': 'block_resize', 'arguments': {'size': 18446744073709551104L, 'node_name': 'node1'}}
644
+{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter type for 'size', expected: integer"}}
645
+{'execute': 'block_resize', 'arguments': {'size': -9223372036854775808, 'node_name': 'node1'}}
646
+{u'error': {u'class': u'GenericError', u'desc': u"Parameter 'size' expects a >0 size"}}
647
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
648
file format: IMGFMT
649
virtual size: 0 (0 bytes)
650
-*** done
651
+encrypted: yes
652
+Format specific information:
653
+ ivgen alg: plain64
654
+ hash alg: sha256
655
+ cipher alg: aes-256
656
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
657
+ cipher mode: xts
658
+ slots:
659
+ [0]:
660
+ active: true
661
+ iters: XXX
662
+ key offset: 4096
663
+ stripes: 4000
664
+ [1]:
665
+ active: false
666
+ key offset: 262144
667
+ [2]:
668
+ active: false
669
+ key offset: 520192
670
+ [3]:
671
+ active: false
672
+ key offset: 778240
673
+ [4]:
674
+ active: false
675
+ key offset: 1036288
676
+ [5]:
677
+ active: false
678
+ key offset: 1294336
679
+ [6]:
680
+ active: false
681
+ key offset: 1552384
682
+ [7]:
683
+ active: false
684
+ key offset: 1810432
685
+ payload offset: 2068480
686
+ master key iters: XXX
687
+
688
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
689
index XXXXXXX..XXXXXXX 100644
690
--- a/tests/qemu-iotests/group
691
+++ b/tests/qemu-iotests/group
692
@@ -XXX,XX +XXX,XX @@
693
207 rw auto
694
208 rw auto quick
695
209 rw auto quick
696
+210 rw auto
697
# TODO The following commented out tests need to be reworked to work
698
# with the x-blockdev-create job
699
-#210 rw auto
700
#211 rw auto quick
701
#212 rw auto quick
702
#213 rw auto quick
703
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
704
index XXXXXXX..XXXXXXX 100644
705
--- a/tests/qemu-iotests/iotests.py
706
+++ b/tests/qemu-iotests/iotests.py
707
@@ -XXX,XX +XXX,XX @@ def qemu_img_pipe(*args):
708
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
709
return subp.communicate()[0]
710
711
-def img_info_log(filename, filter_path=None):
712
- output = qemu_img_pipe('info', '-f', imgfmt, filename)
713
+def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]):
714
+ args = [ 'info' ]
715
+ if imgopts:
716
+ args.append('--image-opts')
717
+ else:
718
+ args += [ '-f', imgfmt ]
719
+ args += extra_args
720
+ args.append(filename)
721
+
722
+ output = qemu_img_pipe(*args)
723
if not filter_path:
724
filter_path = filename
725
log(filter_img_info(output, filter_path))
726
--
256
--
727
2.13.6
257
2.13.6
728
258
729
259
diff view generated by jsdifflib
1
.bdrv_co_create() is supposed to return 0 on success, but vhdx could
1
bdrv_drained_begin() waits for the completion of requests in the whole
2
return a positive value instead. Fix this.
2
subtree, but it only actually keeps its immediate bs parameter quiesced
3
until bdrv_drained_end().
4
5
Add a version that keeps the whole subtree drained. As of this commit,
6
graph changes cannot be allowed during a subtree drained section, but
7
this will be fixed soon.
3
8
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
10
---
8
block/vhdx.c | 2 +-
11
include/block/block.h | 13 +++++++++++++
9
1 file changed, 1 insertion(+), 1 deletion(-)
12
block/io.c | 54 ++++++++++++++++++++++++++++++++++++++++-----------
13
2 files changed, 56 insertions(+), 11 deletions(-)
10
14
11
diff --git a/block/vhdx.c b/block/vhdx.c
15
diff --git a/include/block/block.h b/include/block/block.h
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/block/vhdx.c
17
--- a/include/block/block.h
14
+++ b/block/vhdx.c
18
+++ b/include/block/block.h
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
19
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
16
goto delete_and_exit;
20
void bdrv_drained_begin(BlockDriverState *bs);
21
22
/**
23
+ * Like bdrv_drained_begin, but recursively begins a quiesced section for
24
+ * exclusive access to all child nodes as well.
25
+ *
26
+ * Graph changes are not allowed during a subtree drain section.
27
+ */
28
+void bdrv_subtree_drained_begin(BlockDriverState *bs);
29
+
30
+/**
31
* bdrv_drained_end:
32
*
33
* End a quiescent section started by bdrv_drained_begin().
34
*/
35
void bdrv_drained_end(BlockDriverState *bs);
36
37
+/**
38
+ * End a quiescent section started by bdrv_subtree_drained_begin().
39
+ */
40
+void bdrv_subtree_drained_end(BlockDriverState *bs);
41
+
42
void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
43
Error **errp);
44
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
45
diff --git a/block/io.c b/block/io.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block/io.c
48
+++ b/block/io.c
49
@@ -XXX,XX +XXX,XX @@ typedef struct {
50
BlockDriverState *bs;
51
bool done;
52
bool begin;
53
+ bool recursive;
54
BdrvChild *parent;
55
} BdrvCoDrainData;
56
57
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
58
return waited;
59
}
60
61
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
62
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
63
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
64
+ BdrvChild *parent);
65
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
66
+ BdrvChild *parent);
67
68
static void bdrv_co_drain_bh_cb(void *opaque)
69
{
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
71
72
bdrv_dec_in_flight(bs);
73
if (data->begin) {
74
- bdrv_do_drained_begin(bs, data->parent);
75
+ bdrv_do_drained_begin(bs, data->recursive, data->parent);
76
} else {
77
- bdrv_do_drained_end(bs, data->parent);
78
+ bdrv_do_drained_end(bs, data->recursive, data->parent);
17
}
79
}
18
80
19
-
81
data->done = true;
20
+ ret = 0;
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
21
delete_and_exit:
83
}
22
blk_unref(blk);
84
23
bdrv_unref(bs);
85
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
86
- bool begin, BdrvChild *parent)
87
+ bool begin, bool recursive,
88
+ BdrvChild *parent)
89
{
90
BdrvCoDrainData data;
91
92
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
93
.bs = bs,
94
.done = false,
95
.begin = begin,
96
+ .recursive = recursive,
97
.parent = parent,
98
};
99
bdrv_inc_in_flight(bs);
100
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
101
assert(data.done);
102
}
103
104
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
105
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
106
+ BdrvChild *parent)
107
{
108
+ BdrvChild *child, *next;
109
+
110
if (qemu_in_coroutine()) {
111
- bdrv_co_yield_to_drain(bs, true, parent);
112
+ bdrv_co_yield_to_drain(bs, true, recursive, parent);
113
return;
114
}
115
116
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
117
bdrv_parent_drained_begin(bs, parent);
118
bdrv_drain_invoke(bs, true, false);
119
bdrv_drain_recurse(bs);
120
+
121
+ if (recursive) {
122
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
123
+ bdrv_do_drained_begin(child->bs, true, child);
124
+ }
125
+ }
126
}
127
128
void bdrv_drained_begin(BlockDriverState *bs)
129
{
130
- bdrv_do_drained_begin(bs, NULL);
131
+ bdrv_do_drained_begin(bs, false, NULL);
132
+}
133
+
134
+void bdrv_subtree_drained_begin(BlockDriverState *bs)
135
+{
136
+ bdrv_do_drained_begin(bs, true, NULL);
137
}
138
139
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
140
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
141
+ BdrvChild *parent)
142
{
143
+ BdrvChild *child, *next;
144
int old_quiesce_counter;
145
146
if (qemu_in_coroutine()) {
147
- bdrv_co_yield_to_drain(bs, false, parent);
148
+ bdrv_co_yield_to_drain(bs, false, recursive, parent);
149
return;
150
}
151
assert(bs->quiesce_counter > 0);
152
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
153
if (old_quiesce_counter == 1) {
154
aio_enable_external(bdrv_get_aio_context(bs));
155
}
156
+
157
+ if (recursive) {
158
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
159
+ bdrv_do_drained_end(child->bs, true, child);
160
+ }
161
+ }
162
}
163
164
void bdrv_drained_end(BlockDriverState *bs)
165
{
166
- bdrv_do_drained_end(bs, NULL);
167
+ bdrv_do_drained_end(bs, false, NULL);
168
+}
169
+
170
+void bdrv_subtree_drained_end(BlockDriverState *bs)
171
+{
172
+ bdrv_do_drained_end(bs, true, NULL);
173
}
174
175
/*
24
--
176
--
25
2.13.6
177
2.13.6
26
178
27
179
diff view generated by jsdifflib
1
So far we relied on job->ret and strerror() to produce an error message
1
Add a subtree drain version to the existing test cases.
2
for failed jobs. Not surprisingly, this tends to result in completely
3
useless messages.
4
5
This adds a Job.error field that can contain an error string for a
6
failing job, and a parameter to job_completed() that sets the field. As
7
a default, if NULL is passed, we continue to use strerror(job->ret).
8
9
All existing callers are changed to pass NULL. They can be improved in
10
separate patches.
11
2
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Jeff Cody <jcody@redhat.com>
15
---
4
---
16
include/qemu/job.h | 7 ++++++-
5
tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++-
17
block/backup.c | 2 +-
6
1 file changed, 26 insertions(+), 1 deletion(-)
18
block/commit.c | 2 +-
19
block/mirror.c | 2 +-
20
block/stream.c | 2 +-
21
job-qmp.c | 9 ++-------
22
job.c | 16 ++++++++++++++--
23
tests/test-bdrv-drain.c | 2 +-
24
tests/test-blockjob-txn.c | 2 +-
25
tests/test-blockjob.c | 2 +-
26
10 files changed, 29 insertions(+), 17 deletions(-)
27
7
28
diff --git a/include/qemu/job.h b/include/qemu/job.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/qemu/job.h
31
+++ b/include/qemu/job.h
32
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
33
/** Estimated progress_current value at the completion of the job */
34
int64_t progress_total;
35
36
+ /** Error string for a failed job (NULL if, and only if, job->ret == 0) */
37
+ char *error;
38
+
39
/** ret code passed to job_completed. */
40
int ret;
41
42
@@ -XXX,XX +XXX,XX @@ void job_transition_to_ready(Job *job);
43
/**
44
* @job: The job being completed.
45
* @ret: The status code.
46
+ * @error: The error message for a failing job (only with @ret < 0). If @ret is
47
+ * negative, but NULL is given for @error, strerror() is used.
48
*
49
* Marks @job as completed. If @ret is non-zero, the job transaction it is part
50
* of is aborted. If @ret is zero, the job moves into the WAITING state. If it
51
* is the last job to complete in its transaction, all jobs in the transaction
52
* move from WAITING to PENDING.
53
*/
54
-void job_completed(Job *job, int ret);
55
+void job_completed(Job *job, int ret, Error *error);
56
57
/** Asynchronously complete the specified @job. */
58
void job_complete(Job *job, Error **errp);
59
diff --git a/block/backup.c b/block/backup.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block/backup.c
62
+++ b/block/backup.c
63
@@ -XXX,XX +XXX,XX @@ static void backup_complete(Job *job, void *opaque)
64
{
65
BackupCompleteData *data = opaque;
66
67
- job_completed(job, data->ret);
68
+ job_completed(job, data->ret, NULL);
69
g_free(data);
70
}
71
72
diff --git a/block/commit.c b/block/commit.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/block/commit.c
75
+++ b/block/commit.c
76
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
77
* bdrv_set_backing_hd() to fail. */
78
block_job_remove_all_bdrv(bjob);
79
80
- job_completed(job, ret);
81
+ job_completed(job, ret, NULL);
82
g_free(data);
83
84
/* If bdrv_drop_intermediate() didn't already do that, remove the commit
85
diff --git a/block/mirror.c b/block/mirror.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/block/mirror.c
88
+++ b/block/mirror.c
89
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
90
blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort);
91
blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort);
92
93
- job_completed(job, data->ret);
94
+ job_completed(job, data->ret, NULL);
95
96
g_free(data);
97
bdrv_drained_end(src);
98
diff --git a/block/stream.c b/block/stream.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/block/stream.c
101
+++ b/block/stream.c
102
@@ -XXX,XX +XXX,XX @@ out:
103
}
104
105
g_free(s->backing_file_str);
106
- job_completed(job, data->ret);
107
+ job_completed(job, data->ret, NULL);
108
g_free(data);
109
}
110
111
diff --git a/job-qmp.c b/job-qmp.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/job-qmp.c
114
+++ b/job-qmp.c
115
@@ -XXX,XX +XXX,XX @@ void qmp_job_dismiss(const char *id, Error **errp)
116
static JobInfo *job_query_single(Job *job, Error **errp)
117
{
118
JobInfo *info;
119
- const char *errmsg = NULL;
120
121
assert(!job_is_internal(job));
122
123
- if (job->ret < 0) {
124
- errmsg = strerror(-job->ret);
125
- }
126
-
127
info = g_new(JobInfo, 1);
128
*info = (JobInfo) {
129
.id = g_strdup(job->id),
130
@@ -XXX,XX +XXX,XX @@ static JobInfo *job_query_single(Job *job, Error **errp)
131
.status = job->status,
132
.current_progress = job->progress_current,
133
.total_progress = job->progress_total,
134
- .has_error = !!errmsg,
135
- .error = g_strdup(errmsg),
136
+ .has_error = !!job->error,
137
+ .error = g_strdup(job->error),
138
};
139
140
return info;
141
diff --git a/job.c b/job.c
142
index XXXXXXX..XXXXXXX 100644
143
--- a/job.c
144
+++ b/job.c
145
@@ -XXX,XX +XXX,XX @@ void job_unref(Job *job)
146
147
QLIST_REMOVE(job, job_list);
148
149
+ g_free(job->error);
150
g_free(job->id);
151
g_free(job);
152
}
153
@@ -XXX,XX +XXX,XX @@ static void job_update_rc(Job *job)
154
job->ret = -ECANCELED;
155
}
156
if (job->ret) {
157
+ if (!job->error) {
158
+ job->error = g_strdup(strerror(-job->ret));
159
+ }
160
job_state_transition(job, JOB_STATUS_ABORTING);
161
}
162
}
163
@@ -XXX,XX +XXX,XX @@ static int job_prepare(Job *job)
164
{
165
if (job->ret == 0 && job->driver->prepare) {
166
job->ret = job->driver->prepare(job);
167
+ job_update_rc(job);
168
}
169
return job->ret;
170
}
171
@@ -XXX,XX +XXX,XX @@ static void job_completed_txn_success(Job *job)
172
}
173
}
174
175
-void job_completed(Job *job, int ret)
176
+void job_completed(Job *job, int ret, Error *error)
177
{
178
assert(job && job->txn && !job_is_completed(job));
179
+
180
job->ret = ret;
181
+ if (error) {
182
+ assert(job->ret < 0);
183
+ job->error = g_strdup(error_get_pretty(error));
184
+ error_free(error);
185
+ }
186
+
187
job_update_rc(job);
188
trace_job_completed(job, ret, job->ret);
189
if (job->ret) {
190
@@ -XXX,XX +XXX,XX @@ void job_cancel(Job *job, bool force)
191
}
192
job_cancel_async(job, force);
193
if (!job_started(job)) {
194
- job_completed(job, -ECANCELED);
195
+ job_completed(job, -ECANCELED, NULL);
196
} else if (job->deferred_to_main_loop) {
197
job_completed_txn_abort(job);
198
} else {
199
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
200
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
201
--- a/tests/test-bdrv-drain.c
10
--- a/tests/test-bdrv-drain.c
202
+++ b/tests/test-bdrv-drain.c
11
+++ b/tests/test-bdrv-drain.c
203
@@ -XXX,XX +XXX,XX @@ typedef struct TestBlockJob {
12
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
204
13
enum drain_type {
205
static void test_job_completed(Job *job, void *opaque)
14
BDRV_DRAIN_ALL,
15
BDRV_DRAIN,
16
+ BDRV_SUBTREE_DRAIN,
17
DRAIN_TYPE_MAX,
18
};
19
20
@@ -XXX,XX +XXX,XX @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
21
switch (drain_type) {
22
case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
23
case BDRV_DRAIN: bdrv_drained_begin(bs); break;
24
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break;
25
default: g_assert_not_reached();
26
}
27
}
28
@@ -XXX,XX +XXX,XX @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
29
switch (drain_type) {
30
case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
31
case BDRV_DRAIN: bdrv_drained_end(bs); break;
32
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break;
33
default: g_assert_not_reached();
34
}
35
}
36
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
37
test_drv_cb_common(BDRV_DRAIN, false);
38
}
39
40
+static void test_drv_cb_drain_subtree(void)
41
+{
42
+ test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
43
+}
44
+
45
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
206
{
46
{
207
- job_completed(job, 0);
47
BlockBackend *blk;
208
+ job_completed(job, 0, NULL);
48
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
49
test_quiesce_common(BDRV_DRAIN, false);
209
}
50
}
210
51
211
static void coroutine_fn test_job_start(void *opaque)
52
+static void test_quiesce_drain_subtree(void)
212
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
53
+{
213
index XXXXXXX..XXXXXXX 100644
54
+ test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
214
--- a/tests/test-blockjob-txn.c
55
+}
215
+++ b/tests/test-blockjob-txn.c
56
+
216
@@ -XXX,XX +XXX,XX @@ static void test_block_job_complete(Job *job, void *opaque)
57
static void test_nested(void)
217
rc = -ECANCELED;
58
{
218
}
59
BlockBackend *blk;
219
60
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
220
- job_completed(job, rc);
61
/* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
221
+ job_completed(job, rc, NULL);
62
int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
222
bdrv_unref(bs);
63
(inner != BDRV_DRAIN_ALL);
64
- int backing_quiesce = 0;
65
+ int backing_quiesce = (outer == BDRV_SUBTREE_DRAIN) +
66
+ (inner == BDRV_SUBTREE_DRAIN);
67
int backing_cb_cnt = (outer != BDRV_DRAIN) +
68
(inner != BDRV_DRAIN);
69
70
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_drain(void)
71
test_blockjob_common(BDRV_DRAIN);
223
}
72
}
224
73
225
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
74
+static void test_blockjob_drain_subtree(void)
226
index XXXXXXX..XXXXXXX 100644
75
+{
227
--- a/tests/test-blockjob.c
76
+ test_blockjob_common(BDRV_SUBTREE_DRAIN);
228
+++ b/tests/test-blockjob.c
77
+}
229
@@ -XXX,XX +XXX,XX @@ static void cancel_job_completed(Job *job, void *opaque)
78
+
79
int main(int argc, char **argv)
230
{
80
{
231
CancelJob *s = opaque;
81
bdrv_init();
232
s->completed = true;
82
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
233
- job_completed(job, 0);
83
234
+ job_completed(job, 0, NULL);
84
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
85
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
86
+ g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
87
+ test_drv_cb_drain_subtree);
88
89
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
90
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
91
+ g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
92
+ test_quiesce_drain_subtree);
93
94
g_test_add_func("/bdrv-drain/nested", test_nested);
95
96
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
97
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
98
+ g_test_add_func("/bdrv-drain/blockjob/drain_subtree",
99
+ test_blockjob_drain_subtree);
100
101
return g_test_run();
235
}
102
}
236
237
static void cancel_job_complete(Job *job, Error **errp)
238
--
103
--
239
2.13.6
104
2.13.6
240
105
241
106
diff view generated by jsdifflib
1
This rewrites the test case 207 to work with the new x-blockdev-create
1
If bdrv_do_drained_begin/end() are called in coroutine context, they
2
job rather than the old synchronous version of the command.
2
first use a BH to get out of the coroutine context. Call some existing
3
3
tests again from a coroutine to cover this code path.
4
Most of the test cases stay the same as before (the exception being some
5
improved 'size' options that allow distinguishing which command created
6
the image), but in order to be able to implement proper job handling,
7
the test case is rewritten in Python.
8
4
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
---
6
---
12
tests/qemu-iotests/207 | 440 ++++++++++++++++++++-------------------------
7
tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
13
tests/qemu-iotests/207.out | 107 +++++------
8
1 file changed, 59 insertions(+)
14
tests/qemu-iotests/group | 6 +-
15
3 files changed, 257 insertions(+), 296 deletions(-)
16
9
17
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
18
index XXXXXXX..XXXXXXX 100755
11
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/207
12
--- a/tests/test-bdrv-drain.c
20
+++ b/tests/qemu-iotests/207
13
+++ b/tests/test-bdrv-drain.c
21
@@ -XXX,XX +XXX,XX @@
14
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
22
-#!/bin/bash
15
*aio_ret = ret;
23
+#!/usr/bin/env python
16
}
24
#
17
25
# Test ssh image creation
18
+typedef struct CallInCoroutineData {
26
#
19
+ void (*entry)(void);
27
# Copyright (C) 2018 Red Hat, Inc.
20
+ bool done;
28
#
21
+} CallInCoroutineData;
29
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
30
+#
31
# This program is free software; you can redistribute it and/or modify
32
# it under the terms of the GNU General Public License as published by
33
# the Free Software Foundation; either version 2 of the License, or
34
@@ -XXX,XX +XXX,XX @@
35
# along with this program. If not, see <http://www.gnu.org/licenses/>.
36
#
37
38
-# creator
39
-owner=kwolf@redhat.com
40
-
41
-seq=`basename $0`
42
-echo "QA output created by $seq"
43
-
44
-here=`pwd`
45
-status=1    # failure is the default!
46
-
47
-# get standard environment, filters and checks
48
-. ./common.rc
49
-. ./common.filter
50
-
51
-_supported_fmt raw
52
-_supported_proto ssh
53
-_supported_os Linux
54
-
55
-function do_run_qemu()
56
-{
57
- echo Testing: "$@"
58
- $QEMU -nographic -qmp stdio -serial none "$@"
59
- echo
60
-}
61
-
62
-function run_qemu()
63
-{
64
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
65
- | _filter_qemu | _filter_imgfmt \
66
- | _filter_actual_image_size
67
-}
68
-
69
-echo
70
-echo "=== Successful image creation (defaults) ==="
71
-echo
72
-
73
-run_qemu <<EOF
74
-{ "execute": "qmp_capabilities" }
75
-{ "execute": "x-blockdev-create",
76
- "arguments": {
77
- "driver": "ssh",
78
- "location": {
79
- "path": "$TEST_IMG_FILE",
80
- "server": {
81
- "host": "127.0.0.1",
82
- "port": "22"
83
- }
84
- },
85
- "size": 4194304
86
- }
87
-}
88
-{ "execute": "quit" }
89
-EOF
90
-
91
-_img_info | _filter_img_info
92
-echo
93
-TEST_IMG=$TEST_IMG_FILE _img_info | _filter_img_info
94
-
95
-echo
96
-echo "=== Test host-key-check options ==="
97
-echo
98
-
99
-run_qemu <<EOF
100
-{ "execute": "qmp_capabilities" }
101
-{ "execute": "x-blockdev-create",
102
- "arguments": {
103
- "driver": "ssh",
104
- "location": {
105
- "path": "$TEST_IMG_FILE",
106
- "server": {
107
- "host": "127.0.0.1",
108
- "port": "22"
109
- },
110
- "host-key-check": {
111
- "mode": "none"
112
- }
113
- },
114
- "size": 8388608
115
- }
116
-}
117
-{ "execute": "quit" }
118
-EOF
119
-
120
-_img_info | _filter_img_info
121
-
122
-run_qemu <<EOF
123
-{ "execute": "qmp_capabilities" }
124
-{ "execute": "x-blockdev-create",
125
- "arguments": {
126
- "driver": "ssh",
127
- "location": {
128
- "path": "$TEST_IMG_FILE",
129
- "server": {
130
- "host": "127.0.0.1",
131
- "port": "22"
132
- },
133
- "host-key-check": {
134
- "mode": "known_hosts"
135
- }
136
- },
137
- "size": 4194304
138
- }
139
-}
140
-{ "execute": "quit" }
141
-EOF
142
-
143
-_img_info | _filter_img_info
144
-
145
-
146
-key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
147
- cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1)
148
-
149
-run_qemu <<EOF
150
-{ "execute": "qmp_capabilities" }
151
-{ "execute": "x-blockdev-create",
152
- "arguments": {
153
- "driver": "ssh",
154
- "location": {
155
- "path": "$TEST_IMG_FILE",
156
- "server": {
157
- "host": "127.0.0.1",
158
- "port": "22"
159
- },
160
- "host-key-check": {
161
- "mode": "hash",
162
- "type": "md5",
163
- "hash": "wrong"
164
- }
165
- },
166
- "size": 8388608
167
- }
168
-}
169
-{ "execute": "x-blockdev-create",
170
- "arguments": {
171
- "driver": "ssh",
172
- "location": {
173
- "path": "$TEST_IMG_FILE",
174
- "server": {
175
- "host": "127.0.0.1",
176
- "port": "22"
177
- },
178
- "host-key-check": {
179
- "mode": "hash",
180
- "type": "md5",
181
- "hash": "$key"
182
- }
183
- },
184
- "size": 8388608
185
- }
186
-}
187
-{ "execute": "quit" }
188
-EOF
189
-
190
-_img_info | _filter_img_info
191
-
192
-
193
-key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
194
- cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1)
195
-
196
-run_qemu <<EOF
197
-{ "execute": "qmp_capabilities" }
198
-{ "execute": "x-blockdev-create",
199
- "arguments": {
200
- "driver": "ssh",
201
- "location": {
202
- "path": "$TEST_IMG_FILE",
203
- "server": {
204
- "host": "127.0.0.1",
205
- "port": "22"
206
- },
207
- "host-key-check": {
208
- "mode": "hash",
209
- "type": "sha1",
210
- "hash": "wrong"
211
- }
212
- },
213
- "size": 4194304
214
- }
215
-}
216
-{ "execute": "x-blockdev-create",
217
- "arguments": {
218
- "driver": "ssh",
219
- "location": {
220
- "path": "$TEST_IMG_FILE",
221
- "server": {
222
- "host": "127.0.0.1",
223
- "port": "22"
224
- },
225
- "host-key-check": {
226
- "mode": "hash",
227
- "type": "sha1",
228
- "hash": "$key"
229
- }
230
- },
231
- "size": 4194304
232
- }
233
-}
234
-{ "execute": "quit" }
235
-EOF
236
-
237
-_img_info | _filter_img_info
238
-
239
-echo
240
-echo "=== Invalid path and user ==="
241
-echo
242
-
243
-run_qemu <<EOF
244
-{ "execute": "qmp_capabilities" }
245
-{ "execute": "x-blockdev-create",
246
- "arguments": {
247
- "driver": "ssh",
248
- "location": {
249
- "path": "/this/is/not/an/existing/path",
250
- "server": {
251
- "host": "127.0.0.1",
252
- "port": "22"
253
- }
254
- },
255
- "size": 4194304
256
- }
257
-}
258
-{ "execute": "x-blockdev-create",
259
- "arguments": {
260
- "driver": "ssh",
261
- "location": {
262
- "path": "$TEST_IMG_FILE",
263
- "user": "invalid user",
264
- "server": {
265
- "host": "127.0.0.1",
266
- "port": "22"
267
- }
268
- },
269
- "size": 4194304
270
- }
271
-}
272
-{ "execute": "quit" }
273
-EOF
274
-
275
-# success, all done
276
-echo "*** done"
277
-rm -f $seq.full
278
-status=0
279
+import iotests
280
+import subprocess
281
+import re
282
+
22
+
283
+iotests.verify_image_format(supported_fmts=['raw'])
23
+static coroutine_fn void call_in_coroutine_entry(void *opaque)
284
+iotests.verify_protocol(supported=['ssh'])
24
+{
25
+ CallInCoroutineData *data = opaque;
285
+
26
+
286
+def filter_hash(msg):
27
+ data->entry();
287
+ return re.sub("'hash': '[0-9a-f]+'", "'hash': HASH", msg)
28
+ data->done = true;
29
+}
288
+
30
+
289
+def blockdev_create(vm, options):
31
+static void call_in_coroutine(void (*entry)(void))
290
+ result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options,
32
+{
291
+ filters=[iotests.filter_testfiles, filter_hash])
33
+ Coroutine *co;
34
+ CallInCoroutineData data = {
35
+ .entry = entry,
36
+ .done = false,
37
+ };
292
+
38
+
293
+ if 'return' in result:
39
+ co = qemu_coroutine_create(call_in_coroutine_entry, &data);
294
+ assert result['return'] == {}
40
+ qemu_coroutine_enter(co);
295
+ vm.run_job('job0')
41
+ while (!data.done) {
296
+ iotests.log("")
42
+ aio_poll(qemu_get_aio_context(), true);
43
+ }
44
+}
297
+
45
+
298
+with iotests.FilePath('t.img') as disk_path, \
46
enum drain_type {
299
+ iotests.VM() as vm:
47
BDRV_DRAIN_ALL,
48
BDRV_DRAIN,
49
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_subtree(void)
50
test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
51
}
52
53
+static void test_drv_cb_co_drain(void)
54
+{
55
+ call_in_coroutine(test_drv_cb_drain);
56
+}
300
+
57
+
301
+ remote_path = iotests.remote_filename(disk_path)
58
+static void test_drv_cb_co_drain_subtree(void)
59
+{
60
+ call_in_coroutine(test_drv_cb_drain_subtree);
61
+}
302
+
62
+
303
+ #
63
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
304
+ # Successful image creation (defaults)
64
{
305
+ #
65
BlockBackend *blk;
306
+ iotests.log("=== Successful image creation (defaults) ===")
66
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain_subtree(void)
307
+ iotests.log("")
67
test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
68
}
69
70
+static void test_quiesce_co_drain(void)
71
+{
72
+ call_in_coroutine(test_quiesce_drain);
73
+}
308
+
74
+
309
+ vm.launch()
75
+static void test_quiesce_co_drain_subtree(void)
310
+ blockdev_create(vm, { 'driver': 'ssh',
76
+{
311
+ 'location': {
77
+ call_in_coroutine(test_quiesce_drain_subtree);
312
+ 'path': disk_path,
78
+}
313
+ 'server': {
314
+ 'host': '127.0.0.1',
315
+ 'port': '22'
316
+ }
317
+ },
318
+ 'size': 4194304 })
319
+ vm.shutdown()
320
+
79
+
321
+ iotests.img_info_log(remote_path, filter_path=disk_path)
80
static void test_nested(void)
322
+ iotests.log("")
81
{
323
+ iotests.img_info_log(disk_path)
82
BlockBackend *blk;
83
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
84
g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
85
test_drv_cb_drain_subtree);
86
87
+ // XXX bdrv_drain_all() doesn't work in coroutine context
88
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain);
89
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree",
90
+ test_drv_cb_co_drain_subtree);
324
+
91
+
325
+ #
326
+ # Test host-key-check options
327
+ #
328
+ iotests.log("=== Test host-key-check options ===")
329
+ iotests.log("")
330
+
92
+
331
+ vm.launch()
93
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
332
+ blockdev_create(vm, { 'driver': 'ssh',
94
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
333
+ 'location': {
95
g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
334
+ 'path': disk_path,
96
test_quiesce_drain_subtree);
335
+ 'server': {
97
336
+ 'host': '127.0.0.1',
98
+ // XXX bdrv_drain_all() doesn't work in coroutine context
337
+ 'port': '22'
99
+ g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain);
338
+ },
100
+ g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree",
339
+ 'host-key-check': {
101
+ test_quiesce_co_drain_subtree);
340
+ 'mode': 'none'
341
+ }
342
+ },
343
+ 'size': 8388608 })
344
+ vm.shutdown()
345
+
102
+
346
+ iotests.img_info_log(remote_path, filter_path=disk_path)
103
g_test_add_func("/bdrv-drain/nested", test_nested);
347
+
104
348
+ vm.launch()
105
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
349
+ blockdev_create(vm, { 'driver': 'ssh',
350
+ 'location': {
351
+ 'path': disk_path,
352
+ 'server': {
353
+ 'host': '127.0.0.1',
354
+ 'port': '22'
355
+ },
356
+ 'host-key-check': {
357
+ 'mode': 'known_hosts'
358
+ }
359
+ },
360
+ 'size': 4194304 })
361
+ vm.shutdown()
362
+
363
+ iotests.img_info_log(remote_path, filter_path=disk_path)
364
+
365
+ md5_key = subprocess.check_output(
366
+ 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
367
+ 'cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1',
368
+ shell=True).rstrip()
369
+
370
+ vm.launch()
371
+ blockdev_create(vm, { 'driver': 'ssh',
372
+ 'location': {
373
+ 'path': disk_path,
374
+ 'server': {
375
+ 'host': '127.0.0.1',
376
+ 'port': '22'
377
+ },
378
+ 'host-key-check': {
379
+ 'mode': 'hash',
380
+ 'type': 'md5',
381
+ 'hash': 'wrong',
382
+ }
383
+ },
384
+ 'size': 2097152 })
385
+ blockdev_create(vm, { 'driver': 'ssh',
386
+ 'location': {
387
+ 'path': disk_path,
388
+ 'server': {
389
+ 'host': '127.0.0.1',
390
+ 'port': '22'
391
+ },
392
+ 'host-key-check': {
393
+ 'mode': 'hash',
394
+ 'type': 'md5',
395
+ 'hash': md5_key,
396
+ }
397
+ },
398
+ 'size': 8388608 })
399
+ vm.shutdown()
400
+
401
+ iotests.img_info_log(remote_path, filter_path=disk_path)
402
+
403
+ sha1_key = subprocess.check_output(
404
+ 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
405
+ 'cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1',
406
+ shell=True).rstrip()
407
+
408
+ vm.launch()
409
+ blockdev_create(vm, { 'driver': 'ssh',
410
+ 'location': {
411
+ 'path': disk_path,
412
+ 'server': {
413
+ 'host': '127.0.0.1',
414
+ 'port': '22'
415
+ },
416
+ 'host-key-check': {
417
+ 'mode': 'hash',
418
+ 'type': 'sha1',
419
+ 'hash': 'wrong',
420
+ }
421
+ },
422
+ 'size': 2097152 })
423
+ blockdev_create(vm, { 'driver': 'ssh',
424
+ 'location': {
425
+ 'path': disk_path,
426
+ 'server': {
427
+ 'host': '127.0.0.1',
428
+ 'port': '22'
429
+ },
430
+ 'host-key-check': {
431
+ 'mode': 'hash',
432
+ 'type': 'sha1',
433
+ 'hash': sha1_key,
434
+ }
435
+ },
436
+ 'size': 4194304 })
437
+ vm.shutdown()
438
+
439
+ iotests.img_info_log(remote_path, filter_path=disk_path)
440
+
441
+ #
442
+ # Invalid path and user
443
+ #
444
+ iotests.log("=== Invalid path and user ===")
445
+ iotests.log("")
446
+
447
+ vm.launch()
448
+ blockdev_create(vm, { 'driver': 'ssh',
449
+ 'location': {
450
+ 'path': '/this/is/not/an/existing/path',
451
+ 'server': {
452
+ 'host': '127.0.0.1',
453
+ 'port': '22'
454
+ },
455
+ 'host-key-check': {
456
+ 'mode': 'none'
457
+ }
458
+ },
459
+ 'size': 4194304 })
460
+ blockdev_create(vm, { 'driver': 'ssh',
461
+ 'location': {
462
+ 'path': disk_path,
463
+ 'user': 'invalid user',
464
+ 'server': {
465
+ 'host': '127.0.0.1',
466
+ 'port': '22'
467
+ },
468
+ 'host-key-check': {
469
+ 'mode': 'none'
470
+ }
471
+ },
472
+ 'size': 4194304 })
473
+ vm.shutdown()
474
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
475
index XXXXXXX..XXXXXXX 100644
476
--- a/tests/qemu-iotests/207.out
477
+++ b/tests/qemu-iotests/207.out
478
@@ -XXX,XX +XXX,XX @@
479
-QA output created by 207
480
-
481
=== Successful image creation (defaults) ===
482
483
-Testing:
484
-QMP_VERSION
485
-{"return": {}}
486
-{"return": {}}
487
-{"return": {}}
488
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
489
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
490
+{u'return': {}}
491
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
492
+{u'return': {}}
493
494
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
495
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
496
file format: IMGFMT
497
virtual size: 4.0M (4194304 bytes)
498
499
-image: TEST_DIR/t.IMGFMT
500
+
501
+image: TEST_IMG
502
file format: IMGFMT
503
virtual size: 4.0M (4194304 bytes)
504
505
=== Test host-key-check options ===
506
507
-Testing:
508
-QMP_VERSION
509
-{"return": {}}
510
-{"return": {}}
511
-{"return": {}}
512
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
513
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}}
514
+{u'return': {}}
515
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
516
+{u'return': {}}
517
518
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
519
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
520
file format: IMGFMT
521
virtual size: 8.0M (8388608 bytes)
522
-Testing:
523
-QMP_VERSION
524
-{"return": {}}
525
-{"return": {}}
526
-{"return": {}}
527
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
528
-
529
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
530
+
531
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'known_hosts'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
532
+{u'return': {}}
533
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
534
+{u'return': {}}
535
+
536
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
537
file format: IMGFMT
538
virtual size: 4.0M (4194304 bytes)
539
-Testing:
540
-QMP_VERSION
541
-{"return": {}}
542
-{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
543
-{"return": {}}
544
-{"return": {}}
545
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
546
-
547
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
548
+
549
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}}
550
+{u'return': {}}
551
+Job failed: remote host key does not match host_key_check 'wrong'
552
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
553
+{u'return': {}}
554
+
555
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}}
556
+{u'return': {}}
557
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
558
+{u'return': {}}
559
+
560
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
561
file format: IMGFMT
562
virtual size: 8.0M (8388608 bytes)
563
-Testing:
564
-QMP_VERSION
565
-{"return": {}}
566
-{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
567
-{"return": {}}
568
-{"return": {}}
569
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
570
-
571
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
572
+
573
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}}
574
+{u'return': {}}
575
+Job failed: remote host key does not match host_key_check 'wrong'
576
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
577
+{u'return': {}}
578
+
579
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
580
+{u'return': {}}
581
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
582
+{u'return': {}}
583
+
584
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
585
file format: IMGFMT
586
virtual size: 4.0M (4194304 bytes)
587
588
=== Invalid path and user ===
589
590
-Testing:
591
-QMP_VERSION
592
-{"return": {}}
593
-{"error": {"class": "GenericError", "desc": "failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)"}}
594
-{"error": {"class": "GenericError", "desc": "failed to authenticate using publickey authentication and the identities held by your ssh-agent"}}
595
-{"return": {}}
596
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
597
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': '/this/is/not/an/existing/path', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
598
+{u'return': {}}
599
+Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)
600
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
601
+{u'return': {}}
602
+
603
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'user': 'invalid user', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
604
+{u'return': {}}
605
+Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent
606
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
607
+{u'return': {}}
608
609
-*** done
610
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
611
index XXXXXXX..XXXXXXX 100644
612
--- a/tests/qemu-iotests/group
613
+++ b/tests/qemu-iotests/group
614
@@ -XXX,XX +XXX,XX @@
615
204 rw auto quick
616
205 rw auto quick
617
206 rw auto
618
-# TODO The following commented out tests need to be reworked to work
619
-# with the x-blockdev-create job
620
-#207 rw auto
621
+207 rw auto
622
208 rw auto quick
623
209 rw auto quick
624
+# TODO The following commented out tests need to be reworked to work
625
+# with the x-blockdev-create job
626
#210 rw auto
627
#211 rw auto quick
628
#212 rw auto quick
629
--
106
--
630
2.13.6
107
2.13.6
631
108
632
109
diff view generated by jsdifflib
1
This rewrites the test case 206 to work with the new x-blockdev-create
1
Test that drain sections are correctly propagated through the graph.
2
job rather than the old synchronous version of the command.
3
4
All of the test cases stay the same as before, but in order to be able
5
to implement proper job handling, the test case is rewritten in Python.
6
2
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
4
---
10
tests/qemu-iotests/206 | 680 ++++++++++++++++++---------------------------
5
tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
11
tests/qemu-iotests/206.out | 253 ++++++++++-------
6
1 file changed, 74 insertions(+)
12
tests/qemu-iotests/group | 2 +-
13
3 files changed, 414 insertions(+), 521 deletions(-)
14
7
15
diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
16
index XXXXXXX..XXXXXXX 100755
9
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/206
10
--- a/tests/test-bdrv-drain.c
18
+++ b/tests/qemu-iotests/206
11
+++ b/tests/test-bdrv-drain.c
19
@@ -XXX,XX +XXX,XX @@
12
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
20
-#!/bin/bash
13
blk_unref(blk);
21
+#!/usr/bin/env python
14
}
22
#
15
23
# Test qcow2 and file image creation
16
+static void test_multiparent(void)
24
#
17
+{
25
# Copyright (C) 2018 Red Hat, Inc.
18
+ BlockBackend *blk_a, *blk_b;
26
#
19
+ BlockDriverState *bs_a, *bs_b, *backing;
27
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
20
+ BDRVTestState *a_s, *b_s, *backing_s;
28
+#
29
# This program is free software; you can redistribute it and/or modify
30
# it under the terms of the GNU General Public License as published by
31
# the Free Software Foundation; either version 2 of the License, or
32
@@ -XXX,XX +XXX,XX @@
33
# along with this program. If not, see <http://www.gnu.org/licenses/>.
34
#
35
36
-# creator
37
-owner=kwolf@redhat.com
38
-
39
-seq=`basename $0`
40
-echo "QA output created by $seq"
41
-
42
-here=`pwd`
43
-status=1    # failure is the default!
44
-
45
-# get standard environment, filters and checks
46
-. ./common.rc
47
-. ./common.filter
48
-
49
-_supported_fmt qcow2
50
-_supported_proto file
51
-_supported_os Linux
52
-
53
-function do_run_qemu()
54
-{
55
- echo Testing: "$@"
56
- $QEMU -nographic -qmp stdio -serial none "$@"
57
- echo
58
-}
59
-
60
-function run_qemu()
61
-{
62
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
63
- | _filter_qemu | _filter_imgfmt \
64
- | _filter_actual_image_size
65
-}
66
-
67
-echo
68
-echo "=== Successful image creation (defaults) ==="
69
-echo
70
-
71
-size=$((128 * 1024 * 1024))
72
-
73
-run_qemu <<EOF
74
-{ "execute": "qmp_capabilities" }
75
-{ "execute": "x-blockdev-create",
76
- "arguments": {
77
- "driver": "file",
78
- "filename": "$TEST_IMG",
79
- "size": 0
80
- }
81
-}
82
-{ "execute": "blockdev-add",
83
- "arguments": {
84
- "driver": "file",
85
- "node-name": "imgfile",
86
- "filename": "$TEST_IMG"
87
- }
88
-}
89
-{ "execute": "x-blockdev-create",
90
- "arguments": {
91
- "driver": "$IMGFMT",
92
- "file": "imgfile",
93
- "size": $size
94
- }
95
-}
96
-{ "execute": "quit" }
97
-EOF
98
-
99
-_img_info --format-specific
100
-
101
-echo
102
-echo "=== Successful image creation (inline blockdev-add, explicit defaults) ==="
103
-echo
104
-
105
-# Choose a different size to show that we got a new image
106
-size=$((64 * 1024 * 1024))
107
-
108
-run_qemu <<EOF
109
-{ "execute": "qmp_capabilities" }
110
-{ "execute": "x-blockdev-create",
111
- "arguments": {
112
- "driver": "file",
113
- "filename": "$TEST_IMG",
114
- "size": 0,
115
- "preallocation": "off",
116
- "nocow": false
117
- }
118
-}
119
-{ "execute": "x-blockdev-create",
120
- "arguments": {
121
- "driver": "$IMGFMT",
122
- "file": {
123
- "driver": "file",
124
- "filename": "$TEST_IMG"
125
- },
126
- "size": $size,
127
- "version": "v3",
128
- "cluster-size": 65536,
129
- "preallocation": "off",
130
- "lazy-refcounts": false,
131
- "refcount-bits": 16
132
- }
133
-}
134
-{ "execute": "quit" }
135
-EOF
136
-
137
-_img_info --format-specific
138
-
139
-echo
140
-echo "=== Successful image creation (v3 non-default options) ==="
141
-echo
142
-
143
-# Choose a different size to show that we got a new image
144
-size=$((32 * 1024 * 1024))
145
-
146
-run_qemu <<EOF
147
-{ "execute": "qmp_capabilities" }
148
-{ "execute": "x-blockdev-create",
149
- "arguments": {
150
- "driver": "file",
151
- "filename": "$TEST_IMG",
152
- "size": 0,
153
- "preallocation": "falloc",
154
- "nocow": true
155
- }
156
-}
157
-{ "execute": "x-blockdev-create",
158
- "arguments": {
159
- "driver": "$IMGFMT",
160
- "file": {
161
- "driver": "file",
162
- "filename": "$TEST_IMG"
163
- },
164
- "size": $size,
165
- "version": "v3",
166
- "cluster-size": 2097152,
167
- "preallocation": "metadata",
168
- "lazy-refcounts": true,
169
- "refcount-bits": 1
170
- }
171
-}
172
-{ "execute": "quit" }
173
-EOF
174
-
175
-_img_info --format-specific
176
-
177
-echo
178
-echo "=== Successful image creation (v2 non-default options) ==="
179
-echo
180
-
181
-mv $TEST_IMG $TEST_IMG.base
182
-
183
-run_qemu <<EOF
184
-{ "execute": "qmp_capabilities" }
185
-{ "execute": "x-blockdev-create",
186
- "arguments": {
187
- "driver": "file",
188
- "filename": "$TEST_IMG",
189
- "size": 0
190
- }
191
-}
192
-{ "execute": "x-blockdev-create",
193
- "arguments": {
194
- "driver": "$IMGFMT",
195
- "file": {
196
- "driver": "file",
197
- "filename": "$TEST_IMG"
198
- },
199
- "size": $size,
200
- "backing-file": "$TEST_IMG.base",
201
- "backing-fmt": "qcow2",
202
- "version": "v2",
203
- "cluster-size": 512
204
- }
205
-}
206
-{ "execute": "quit" }
207
-EOF
208
-
209
-_img_info --format-specific
210
-
211
-echo
212
-echo "=== Successful image creation (encrypted) ==="
213
-echo
214
-
215
-run_qemu -object secret,id=keysec0,data="foo" <<EOF
216
-{ "execute": "qmp_capabilities" }
217
-{ "execute": "x-blockdev-create",
218
- "arguments": {
219
- "driver": "$IMGFMT",
220
- "file": {
221
- "driver": "file",
222
- "filename": "$TEST_IMG"
223
- },
224
- "size": $size,
225
- "encrypt": {
226
- "format": "luks",
227
- "key-secret": "keysec0",
228
- "cipher-alg": "twofish-128",
229
- "cipher-mode": "ctr",
230
- "ivgen-alg": "plain64",
231
- "ivgen-hash-alg": "md5",
232
- "hash-alg": "sha1",
233
- "iter-time": 10
234
- }
235
- }
236
-}
237
-{ "execute": "quit" }
238
-EOF
239
-
240
-_img_info --format-specific | _filter_img_info --format-specific
241
-
242
-echo
243
-echo "=== Invalid BlockdevRef ==="
244
-echo
245
-
246
-run_qemu <<EOF
247
-{ "execute": "qmp_capabilities" }
248
-{ "execute": "x-blockdev-create",
249
- "arguments": {
250
- "driver": "$IMGFMT",
251
- "file": "this doesn't exist",
252
- "size": $size
253
- }
254
-}
255
-{ "execute": "quit" }
256
-EOF
257
-
258
-
259
-echo
260
-echo "=== Invalid sizes ==="
261
-echo
262
-
263
-# TODO Negative image sizes aren't handled correctly, but this is a problem
264
-# with QAPI's implementation of the 'size' type and affects other commands as
265
-# well. Once this is fixed, we may want to add a test case here.
266
-
267
-# 1. Misaligned image size
268
-# 2. 2^64 - 512
269
-# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
270
-# 4. 2^63 - 512 (generally valid, but qcow2 can't handle images this size)
271
-
272
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
273
-{ "execute": "qmp_capabilities" }
274
-{ "execute": "x-blockdev-create",
275
- "arguments": {
276
- "driver": "$IMGFMT",
277
- "file": "node0",
278
- "size": 1234
279
- }
280
-}
281
-{ "execute": "x-blockdev-create",
282
- "arguments": {
283
- "driver": "$IMGFMT",
284
- "file": "node0",
285
- "size": 18446744073709551104
286
- }
287
-}
288
-{ "execute": "x-blockdev-create",
289
- "arguments": {
290
- "driver": "$IMGFMT",
291
- "file": "node0",
292
- "size": 9223372036854775808
293
- }
294
-}
295
-{ "execute": "x-blockdev-create",
296
- "arguments": {
297
- "driver": "$IMGFMT",
298
- "file": "node0",
299
- "size": 9223372036854775296
300
- }
301
-}
302
-{ "execute": "quit" }
303
-EOF
304
-
305
-echo
306
-echo "=== Invalid version ==="
307
-echo
308
-
309
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
310
-{ "execute": "qmp_capabilities" }
311
-{ "execute": "x-blockdev-create",
312
- "arguments": {
313
- "driver": "$IMGFMT",
314
- "file": "node0",
315
- "size": 67108864,
316
- "version": "v1"
317
- }
318
-}
319
-{ "execute": "x-blockdev-create",
320
- "arguments": {
321
- "driver": "$IMGFMT",
322
- "file": "node0",
323
- "size": 67108864,
324
- "version": "v2",
325
- "lazy-refcounts": true
326
- }
327
-}
328
-{ "execute": "x-blockdev-create",
329
- "arguments": {
330
- "driver": "$IMGFMT",
331
- "file": "node0",
332
- "size": 67108864,
333
- "version": "v2",
334
- "refcount-bits": 8
335
- }
336
-}
337
-{ "execute": "quit" }
338
-EOF
339
-
340
-echo
341
-echo "=== Invalid backing file options ==="
342
-echo
343
-
344
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
345
-{ "execute": "qmp_capabilities" }
346
-{ "execute": "x-blockdev-create",
347
- "arguments": {
348
- "driver": "$IMGFMT",
349
- "file": "node0",
350
- "size": 67108864,
351
- "backing-file": "/dev/null",
352
- "preallocation": "full"
353
- }
354
-}
355
-{ "execute": "x-blockdev-create",
356
- "arguments": {
357
- "driver": "$IMGFMT",
358
- "file": "node0",
359
- "size": 67108864,
360
- "backing-fmt": "$IMGFMT"
361
- }
362
-}
363
-{ "execute": "quit" }
364
-EOF
365
-
366
-echo
367
-echo "=== Invalid cluster size ==="
368
-echo
369
-
370
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
371
-{ "execute": "qmp_capabilities" }
372
-{ "execute": "x-blockdev-create",
373
- "arguments": {
374
- "driver": "$IMGFMT",
375
- "file": "node0",
376
- "size": 67108864,
377
- "cluster-size": 1234
378
- }
379
-}
380
-{ "execute": "x-blockdev-create",
381
- "arguments": {
382
- "driver": "$IMGFMT",
383
- "file": "node0",
384
- "size": 67108864,
385
- "cluster-size": 128
386
- }
387
-}
388
-{ "execute": "x-blockdev-create",
389
- "arguments": {
390
- "driver": "$IMGFMT",
391
- "file": "node0",
392
- "size": 67108864,
393
- "cluster-size": 4194304
394
- }
395
-}
396
-{ "execute": "x-blockdev-create",
397
- "arguments": {
398
- "driver": "$IMGFMT",
399
- "file": "node0",
400
- "size": 67108864,
401
- "cluster-size": 0
402
- }
403
-}
404
-{ "execute": "x-blockdev-create",
405
- "arguments": {
406
- "driver": "$IMGFMT",
407
- "file": "node0",
408
- "size": 281474976710656,
409
- "cluster-size": 512
410
- }
411
-}
412
-{ "execute": "quit" }
413
-EOF
414
-
415
-echo
416
-echo "=== Invalid refcount width ==="
417
-echo
418
-
419
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
420
-{ "execute": "qmp_capabilities" }
421
-{ "execute": "x-blockdev-create",
422
- "arguments": {
423
- "driver": "$IMGFMT",
424
- "file": "node0",
425
- "size": 67108864,
426
- "refcount-bits": 128
427
- }
428
-}
429
-{ "execute": "x-blockdev-create",
430
- "arguments": {
431
- "driver": "$IMGFMT",
432
- "file": "node0",
433
- "size": 67108864,
434
- "refcount-bits": 0
435
- }
436
-}
437
-{ "execute": "x-blockdev-create",
438
- "arguments": {
439
- "driver": "$IMGFMT",
440
- "file": "node0",
441
- "size": 67108864,
442
- "refcount-bits": 7
443
- }
444
-}
445
-{ "execute": "quit" }
446
-EOF
447
-
448
-# success, all done
449
-echo "*** done"
450
-rm -f $seq.full
451
-status=0
452
+import iotests
453
+from iotests import imgfmt
454
+
21
+
455
+iotests.verify_image_format(supported_fmts=['qcow2'])
22
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
23
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
24
+ &error_abort);
25
+ a_s = bs_a->opaque;
26
+ blk_insert_bs(blk_a, bs_a, &error_abort);
456
+
27
+
457
+def blockdev_create(vm, options):
28
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
458
+ result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options)
29
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
30
+ &error_abort);
31
+ b_s = bs_b->opaque;
32
+ blk_insert_bs(blk_b, bs_b, &error_abort);
459
+
33
+
460
+ if 'return' in result:
34
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
461
+ assert result['return'] == {}
35
+ backing_s = backing->opaque;
462
+ vm.run_job('job0')
36
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
463
+ iotests.log("")
37
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
464
+
38
+
465
+with iotests.FilePath('t.qcow2') as disk_path, \
39
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
466
+ iotests.FilePath('t.qcow2.base') as backing_path, \
40
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
467
+ iotests.VM() as vm:
41
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(a_s->drain_count, ==, 0);
43
+ g_assert_cmpint(b_s->drain_count, ==, 0);
44
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
468
+
45
+
469
+ vm.add_object('secret,id=keysec0,data=foo')
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
470
+
47
+
471
+ #
48
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
472
+ # Successful image creation (defaults)
49
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
473
+ #
50
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
474
+ iotests.log("=== Successful image creation (defaults) ===")
51
+ g_assert_cmpint(a_s->drain_count, ==, 1);
475
+ iotests.log("")
52
+ g_assert_cmpint(b_s->drain_count, ==, 1);
53
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
476
+
54
+
477
+ size = 128 * 1024 * 1024
55
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
478
+
56
+
479
+ vm.launch()
57
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 2);
480
+ blockdev_create(vm, { 'driver': 'file',
58
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
481
+ 'filename': disk_path,
59
+ g_assert_cmpint(backing->quiesce_counter, ==, 2);
482
+ 'size': 0 })
60
+ g_assert_cmpint(a_s->drain_count, ==, 2);
61
+ g_assert_cmpint(b_s->drain_count, ==, 2);
62
+ g_assert_cmpint(backing_s->drain_count, ==, 2);
483
+
63
+
484
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
64
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
485
+ node_name='imgfile')
486
+
65
+
487
+ blockdev_create(vm, { 'driver': imgfmt,
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
488
+ 'file': 'imgfile',
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
489
+ 'size': size })
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
490
+ vm.shutdown()
69
+ g_assert_cmpint(a_s->drain_count, ==, 1);
70
+ g_assert_cmpint(b_s->drain_count, ==, 1);
71
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
491
+
72
+
492
+ iotests.img_info_log(disk_path)
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
493
+
74
+
494
+ #
75
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
495
+ # Successful image creation (inline blockdev-add, explicit defaults)
76
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
496
+ #
77
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
497
+ iotests.log("=== Successful image creation (inline blockdev-add, explicit defaults) ===")
78
+ g_assert_cmpint(a_s->drain_count, ==, 0);
498
+ iotests.log("")
79
+ g_assert_cmpint(b_s->drain_count, ==, 0);
80
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
499
+
81
+
500
+ # Choose a different size to show that we got a new image
82
+ bdrv_unref(backing);
501
+ size = 64 * 1024 * 1024
83
+ bdrv_unref(bs_a);
84
+ bdrv_unref(bs_b);
85
+ blk_unref(blk_a);
86
+ blk_unref(blk_b);
87
+}
502
+
88
+
503
+ vm.launch()
89
504
+ blockdev_create(vm, { 'driver': 'file',
90
typedef struct TestBlockJob {
505
+ 'filename': disk_path,
91
BlockJob common;
506
+ 'size': 0,
92
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
507
+ 'preallocation': 'off',
93
test_quiesce_co_drain_subtree);
508
+ 'nocow': False })
94
509
+
95
g_test_add_func("/bdrv-drain/nested", test_nested);
510
+ blockdev_create(vm, { 'driver': imgfmt,
96
+ g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
511
+ 'file': {
97
512
+ 'driver': 'file',
98
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
513
+ 'filename': disk_path,
99
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
514
+ },
515
+ 'size': size,
516
+ 'version': 'v3',
517
+ 'cluster-size': 65536,
518
+ 'preallocation': 'off',
519
+ 'lazy-refcounts': False,
520
+ 'refcount-bits': 16 })
521
+ vm.shutdown()
522
+
523
+ iotests.img_info_log(disk_path)
524
+
525
+ #
526
+ # Successful image creation (v3 non-default options)
527
+ #
528
+ iotests.log("=== Successful image creation (v3 non-default options) ===")
529
+ iotests.log("")
530
+
531
+ # Choose a different size to show that we got a new image
532
+ size = 32 * 1024 * 1024
533
+
534
+ vm.launch()
535
+ blockdev_create(vm, { 'driver': 'file',
536
+ 'filename': disk_path,
537
+ 'size': 0,
538
+ 'preallocation': 'falloc',
539
+ 'nocow': True })
540
+
541
+ blockdev_create(vm, { 'driver': imgfmt,
542
+ 'file': {
543
+ 'driver': 'file',
544
+ 'filename': disk_path,
545
+ },
546
+ 'size': size,
547
+ 'version': 'v3',
548
+ 'cluster-size': 2097152,
549
+ 'preallocation': 'metadata',
550
+ 'lazy-refcounts': True,
551
+ 'refcount-bits': 1 })
552
+ vm.shutdown()
553
+
554
+ iotests.img_info_log(disk_path)
555
+
556
+ #
557
+ # Successful image creation (v2 non-default options)
558
+ #
559
+ iotests.log("=== Successful image creation (v2 non-default options) ===")
560
+ iotests.log("")
561
+
562
+ vm.launch()
563
+ blockdev_create(vm, { 'driver': 'file',
564
+ 'filename': disk_path,
565
+ 'size': 0 })
566
+
567
+ blockdev_create(vm, { 'driver': imgfmt,
568
+ 'file': {
569
+ 'driver': 'file',
570
+ 'filename': disk_path,
571
+ },
572
+ 'size': size,
573
+ 'backing-file': backing_path,
574
+ 'backing-fmt': 'qcow2',
575
+ 'version': 'v2',
576
+ 'cluster-size': 512 })
577
+ vm.shutdown()
578
+
579
+ iotests.img_info_log(disk_path)
580
+
581
+ #
582
+ # Successful image creation (encrypted)
583
+ #
584
+ iotests.log("=== Successful image creation (encrypted) ===")
585
+ iotests.log("")
586
+
587
+ vm.launch()
588
+ blockdev_create(vm, { 'driver': imgfmt,
589
+ 'file': {
590
+ 'driver': 'file',
591
+ 'filename': disk_path,
592
+ },
593
+ 'size': size,
594
+ 'encrypt': {
595
+ 'format': 'luks',
596
+ 'key-secret': 'keysec0',
597
+ 'cipher-alg': 'twofish-128',
598
+ 'cipher-mode': 'ctr',
599
+ 'ivgen-alg': 'plain64',
600
+ 'ivgen-hash-alg': 'md5',
601
+ 'hash-alg': 'sha1',
602
+ 'iter-time': 10,
603
+ }})
604
+ vm.shutdown()
605
+
606
+ iotests.img_info_log(disk_path)
607
+
608
+ #
609
+ # Invalid BlockdevRef
610
+ #
611
+ iotests.log("=== Invalid BlockdevRef ===")
612
+ iotests.log("")
613
+
614
+ vm.launch()
615
+ blockdev_create(vm, { 'driver': imgfmt,
616
+ 'file': "this doesn't exist",
617
+ 'size': size })
618
+ vm.shutdown()
619
+
620
+ #
621
+ # Invalid sizes
622
+ #
623
+ iotests.log("=== Invalid sizes ===")
624
+
625
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
626
+ # with QAPI's implementation of the 'size' type and affects other commands
627
+ # as well. Once this is fixed, we may want to add a test case here.
628
+ #
629
+ # 1. Misaligned image size
630
+ # 2. 2^64 - 512
631
+ # 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
632
+ # 4. 2^63 - 512 (generally valid, but qcow2 can't handle images this size)
633
+
634
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
635
+
636
+ vm.launch()
637
+ for size in [ 1234, 18446744073709551104, 9223372036854775808,
638
+ 9223372036854775296 ]:
639
+ blockdev_create(vm, { 'driver': imgfmt,
640
+ 'file': 'node0',
641
+ 'size': size })
642
+ vm.shutdown()
643
+
644
+ #
645
+ # Invalid version
646
+ #
647
+ iotests.log("=== Invalid version ===")
648
+
649
+ vm.launch()
650
+ blockdev_create(vm, { 'driver': imgfmt,
651
+ 'file': 'node0',
652
+ 'size': 67108864,
653
+ 'version': 'v1' })
654
+ blockdev_create(vm, { 'driver': imgfmt,
655
+ 'file': 'node0',
656
+ 'size': 67108864,
657
+ 'version': 'v2',
658
+ 'lazy-refcounts': True })
659
+ blockdev_create(vm, { 'driver': imgfmt,
660
+ 'file': 'node0',
661
+ 'size': 67108864,
662
+ 'version': 'v2',
663
+ 'refcount-bits': 8 })
664
+ vm.shutdown()
665
+
666
+ #
667
+ # Invalid backing file options
668
+ #
669
+ iotests.log("=== Invalid backing file options ===")
670
+
671
+ vm.launch()
672
+ blockdev_create(vm, { 'driver': imgfmt,
673
+ 'file': 'node0',
674
+ 'size': 67108864,
675
+ 'backing-file': '/dev/null',
676
+ 'preallocation': 'full' })
677
+ blockdev_create(vm, { 'driver': imgfmt,
678
+ 'file': 'node0',
679
+ 'size': 67108864,
680
+ 'backing-fmt': imgfmt })
681
+ vm.shutdown()
682
+
683
+ #
684
+ # Invalid cluster size
685
+ #
686
+ iotests.log("=== Invalid cluster size ===")
687
+
688
+ vm.launch()
689
+ for csize in [ 1234, 128, 4194304, 0 ]:
690
+ blockdev_create(vm, { 'driver': imgfmt,
691
+ 'file': 'node0',
692
+ 'size': 67108864,
693
+ 'cluster-size': csize })
694
+ blockdev_create(vm, { 'driver': imgfmt,
695
+ 'file': 'node0',
696
+ 'size': 281474976710656,
697
+ 'cluster-size': 512 })
698
+ vm.shutdown()
699
+
700
+ #
701
+ # Invalid refcount width
702
+ #
703
+ iotests.log("=== Invalid refcount width ===")
704
+
705
+ vm.launch()
706
+ for refcount_bits in [ 128, 0, 7 ]:
707
+ blockdev_create(vm, { 'driver': imgfmt,
708
+ 'file': 'node0',
709
+ 'size': 67108864,
710
+ 'refcount-bits': refcount_bits })
711
+ vm.shutdown()
712
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
713
index XXXXXXX..XXXXXXX 100644
714
--- a/tests/qemu-iotests/206.out
715
+++ b/tests/qemu-iotests/206.out
716
@@ -XXX,XX +XXX,XX @@
717
-QA output created by 206
718
-
719
=== Successful image creation (defaults) ===
720
721
-Testing:
722
-QMP_VERSION
723
-{"return": {}}
724
-{"return": {}}
725
-{"return": {}}
726
-{"return": {}}
727
-{"return": {}}
728
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
729
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
730
+{u'return': {}}
731
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
732
+{u'return': {}}
733
+
734
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}
735
+{u'return': {}}
736
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'imgfile', 'size': 134217728}}}
737
+{u'return': {}}
738
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
739
+{u'return': {}}
740
741
-image: TEST_DIR/t.IMGFMT
742
+image: TEST_IMG
743
file format: IMGFMT
744
virtual size: 128M (134217728 bytes)
745
cluster_size: 65536
746
@@ -XXX,XX +XXX,XX @@ Format specific information:
747
748
=== Successful image creation (inline blockdev-add, explicit defaults) ===
749
750
-Testing:
751
-QMP_VERSION
752
-{"return": {}}
753
-{"return": {}}
754
-{"return": {}}
755
-{"return": {}}
756
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
757
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': False, 'preallocation': 'off', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
758
+{u'return': {}}
759
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
760
+{u'return': {}}
761
762
-image: TEST_DIR/t.IMGFMT
763
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'refcount-bits': 16, 'version': 'v3', 'preallocation': 'off', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': False, 'driver': 'qcow2', 'size': 67108864}}}
764
+{u'return': {}}
765
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
766
+{u'return': {}}
767
+
768
+image: TEST_IMG
769
file format: IMGFMT
770
virtual size: 64M (67108864 bytes)
771
cluster_size: 65536
772
@@ -XXX,XX +XXX,XX @@ Format specific information:
773
774
=== Successful image creation (v3 non-default options) ===
775
776
-Testing:
777
-QMP_VERSION
778
-{"return": {}}
779
-{"return": {}}
780
-{"return": {}}
781
-{"return": {}}
782
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
783
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': True, 'preallocation': 'falloc', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
784
+{u'return': {}}
785
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
786
+{u'return': {}}
787
+
788
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 2097152, 'refcount-bits': 1, 'version': 'v3', 'preallocation': 'metadata', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': True, 'driver': 'qcow2', 'size': 33554432}}}
789
+{u'return': {}}
790
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
791
+{u'return': {}}
792
793
-image: TEST_DIR/t.IMGFMT
794
+image: TEST_IMG
795
file format: IMGFMT
796
virtual size: 32M (33554432 bytes)
797
cluster_size: 2097152
798
@@ -XXX,XX +XXX,XX @@ Format specific information:
799
800
=== Successful image creation (v2 non-default options) ===
801
802
-Testing:
803
-QMP_VERSION
804
-{"return": {}}
805
-{"return": {}}
806
-{"return": {}}
807
-{"return": {}}
808
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
809
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
810
+{u'return': {}}
811
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
812
+{u'return': {}}
813
814
-image: TEST_DIR/t.IMGFMT
815
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'backing-fmt': 'qcow2', 'driver': 'qcow2', 'version': 'v2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'backing-file': 'TEST_DIR/PID-t.qcow2.base', 'size': 33554432}}}
816
+{u'return': {}}
817
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
818
+{u'return': {}}
819
+
820
+image: TEST_IMG
821
file format: IMGFMT
822
virtual size: 32M (33554432 bytes)
823
cluster_size: 512
824
-backing file: TEST_DIR/t.IMGFMT.base
825
+backing file: TEST_IMG.base
826
backing file format: IMGFMT
827
Format specific information:
828
compat: 0.10
829
@@ -XXX,XX +XXX,XX @@ Format specific information:
830
831
=== Successful image creation (encrypted) ===
832
833
-Testing: -object secret,id=keysec0,data=foo
834
-QMP_VERSION
835
-{"return": {}}
836
-{"return": {}}
837
-{"return": {}}
838
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
839
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'encrypt': {'key-secret': 'keysec0', 'iter-time': 10, 'cipher-mode': 'ctr', 'ivgen-hash-alg': 'md5', 'cipher-alg': 'twofish-128', 'format': 'luks', 'ivgen-alg': 'plain64', 'hash-alg': 'sha1'}, 'driver': 'qcow2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'size': 33554432}}}
840
+{u'return': {}}
841
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
842
+{u'return': {}}
843
844
-image: TEST_DIR/t.IMGFMT
845
+image: TEST_IMG
846
file format: IMGFMT
847
virtual size: 32M (33554432 bytes)
848
+encrypted: yes
849
+cluster_size: 65536
850
Format specific information:
851
compat: 1.1
852
lazy refcounts: false
853
@@ -XXX,XX +XXX,XX @@ Format specific information:
854
ivgen alg: plain64
855
hash alg: sha1
856
cipher alg: twofish-128
857
- uuid: 00000000-0000-0000-0000-000000000000
858
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
859
format: luks
860
cipher mode: ctr
861
slots:
862
[0]:
863
active: true
864
- iters: 1024
865
+ iters: XXX
866
key offset: 4096
867
stripes: 4000
868
[1]:
869
@@ -XXX,XX +XXX,XX @@ Format specific information:
870
active: false
871
key offset: 462848
872
payload offset: 528384
873
- master key iters: 1024
874
+ master key iters: XXX
875
corrupt: false
876
877
=== Invalid BlockdevRef ===
878
879
-Testing:
880
-QMP_VERSION
881
-{"return": {}}
882
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
883
-{"return": {}}
884
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
885
-
886
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': "this doesn't exist", 'size': 33554432}}}
887
+{u'return': {}}
888
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
889
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
890
+{u'return': {}}
891
892
=== Invalid sizes ===
893
-
894
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
895
-QMP_VERSION
896
-{"return": {}}
897
-{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
898
-{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
899
-{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
900
-{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
901
-{"return": {}}
902
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
903
-
904
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 1234}}}
905
+{u'return': {}}
906
+Job failed: Image size must be a multiple of 512 bytes
907
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
908
+{u'return': {}}
909
+
910
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 18446744073709551104L}}}
911
+{u'return': {}}
912
+Job failed: Could not resize image: Image size cannot be negative
913
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
914
+{u'return': {}}
915
+
916
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775808L}}}
917
+{u'return': {}}
918
+Job failed: Could not resize image: Image size cannot be negative
919
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
920
+{u'return': {}}
921
+
922
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775296}}}
923
+{u'return': {}}
924
+Job failed: Could not resize image: Failed to grow the L1 table: File too large
925
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
926
+{u'return': {}}
927
928
=== Invalid version ===
929
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'version': 'v1', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
930
+{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter 'v1'"}}
931
932
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
933
-QMP_VERSION
934
-{"return": {}}
935
-{"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}}
936
-{"error": {"class": "GenericError", "desc": "Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)"}}
937
-{"error": {"class": "GenericError", "desc": "Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)"}}
938
-{"return": {}}
939
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
940
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'lazy-refcounts': True, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
941
+{u'return': {}}
942
+Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
943
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
944
+{u'return': {}}
945
946
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 8, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
947
+{u'return': {}}
948
+Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
949
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
950
+{u'return': {}}
951
952
=== Invalid backing file options ===
953
-
954
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
955
-QMP_VERSION
956
-{"return": {}}
957
-{"error": {"class": "GenericError", "desc": "Backing file and preallocation cannot be used at the same time"}}
958
-{"error": {"class": "GenericError", "desc": "Backing format cannot be used without backing file"}}
959
-{"return": {}}
960
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
961
-
962
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'full', 'driver': 'qcow2', 'backing-file': '/dev/null', 'file': 'node0', 'size': 67108864}}}
963
+{u'return': {}}
964
+Job failed: Backing file and preallocation cannot be used at the same time
965
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
966
+{u'return': {}}
967
+
968
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'backing-fmt': 'qcow2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
969
+{u'return': {}}
970
+Job failed: Backing format cannot be used without backing file
971
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
972
+{u'return': {}}
973
974
=== Invalid cluster size ===
975
-
976
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
977
-QMP_VERSION
978
-{"return": {}}
979
-{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
980
-{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
981
-{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
982
-{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
983
-{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
984
-{"return": {}}
985
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
986
-
987
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
988
+{u'return': {}}
989
+Job failed: Cluster size must be a power of two between 512 and 2048k
990
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
991
+{u'return': {}}
992
+
993
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
994
+{u'return': {}}
995
+Job failed: Cluster size must be a power of two between 512 and 2048k
996
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
997
+{u'return': {}}
998
+
999
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4194304, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
1000
+{u'return': {}}
1001
+Job failed: Cluster size must be a power of two between 512 and 2048k
1002
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
1003
+{u'return': {}}
1004
+
1005
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
1006
+{u'return': {}}
1007
+Job failed: Cluster size must be a power of two between 512 and 2048k
1008
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
1009
+{u'return': {}}
1010
+
1011
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'qcow2', 'file': 'node0', 'size': 281474976710656}}}
1012
+{u'return': {}}
1013
+Job failed: Could not resize image: Failed to grow the L1 table: File too large
1014
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
1015
+{u'return': {}}
1016
1017
=== Invalid refcount width ===
1018
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
1019
+{u'return': {}}
1020
+Job failed: Refcount width must be a power of two and may not exceed 64 bits
1021
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
1022
+{u'return': {}}
1023
+
1024
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
1025
+{u'return': {}}
1026
+Job failed: Refcount width must be a power of two and may not exceed 64 bits
1027
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
1028
+{u'return': {}}
1029
+
1030
+{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 7, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
1031
+{u'return': {}}
1032
+Job failed: Refcount width must be a power of two and may not exceed 64 bits
1033
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
1034
+{u'return': {}}
1035
1036
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
1037
-QMP_VERSION
1038
-{"return": {}}
1039
-{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
1040
-{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
1041
-{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
1042
-{"return": {}}
1043
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
1044
-
1045
-*** done
1046
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
1047
index XXXXXXX..XXXXXXX 100644
1048
--- a/tests/qemu-iotests/group
1049
+++ b/tests/qemu-iotests/group
1050
@@ -XXX,XX +XXX,XX @@
1051
203 rw auto migration
1052
204 rw auto quick
1053
205 rw auto quick
1054
+206 rw auto
1055
# TODO The following commented out tests need to be reworked to work
1056
# with the x-blockdev-create job
1057
-#206 rw auto
1058
#207 rw auto
1059
208 rw auto quick
1060
209 rw auto quick
1061
--
100
--
1062
2.13.6
101
2.13.6
1063
102
1064
103
diff view generated by jsdifflib
1
This adds two helper functions that are useful for test cases that make
1
We need to remember how many of the drain sections in which a node is
2
use of a non-file protocol (specifically ssh).
2
were recursive (i.e. subtree drain rather than node drain), so that they
3
can be correctly applied when children are added or removed during the
4
drained section.
5
6
With this change, it is safe to modify the graph even inside a
7
bdrv_subtree_drained_begin/end() section.
3
8
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
10
---
8
tests/qemu-iotests/iotests.py | 17 +++++++++++++++++
11
include/block/block.h | 2 --
9
1 file changed, 17 insertions(+)
12
include/block/block_int.h | 5 +++++
10
13
block.c | 32 +++++++++++++++++++++++++++++---
11
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
14
block/io.c | 28 ++++++++++++++++++++++++----
12
index XXXXXXX..XXXXXXX 100644
15
4 files changed, 58 insertions(+), 9 deletions(-)
13
--- a/tests/qemu-iotests/iotests.py
16
14
+++ b/tests/qemu-iotests/iotests.py
17
diff --git a/include/block/block.h b/include/block/block.h
15
@@ -XXX,XX +XXX,XX @@ def file_path(*names):
18
index XXXXXXX..XXXXXXX 100644
16
19
--- a/include/block/block.h
17
return paths[0] if len(paths) == 1 else paths
20
+++ b/include/block/block.h
18
21
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs);
19
+def remote_filename(path):
22
/**
20
+ if imgproto == 'file':
23
* Like bdrv_drained_begin, but recursively begins a quiesced section for
21
+ return path
24
* exclusive access to all child nodes as well.
22
+ elif imgproto == 'ssh':
25
- *
23
+ return "ssh://127.0.0.1%s" % (path)
26
- * Graph changes are not allowed during a subtree drain section.
24
+ else:
27
*/
25
+ raise Exception("Protocol %s not supported" % (imgproto))
28
void bdrv_subtree_drained_begin(BlockDriverState *bs);
26
29
27
class VM(qtest.QEMUQtestMachine):
30
diff --git a/include/block/block_int.h b/include/block/block_int.h
28
'''A QEMU VM'''
31
index XXXXXXX..XXXXXXX 100644
29
@@ -XXX,XX +XXX,XX @@ def verify_image_format(supported_fmts=[], unsupported_fmts=[]):
32
--- a/include/block/block_int.h
30
if not_sup or (imgfmt in unsupported_fmts):
33
+++ b/include/block/block_int.h
31
notrun('not suitable for this image format: %s' % imgfmt)
34
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
32
35
33
+def verify_protocol(supported=[], unsupported=[]):
36
/* Accessed with atomic ops. */
34
+ assert not (supported and unsupported)
37
int quiesce_counter;
35
+
38
+ int recursive_quiesce_counter;
36
+ if 'generic' in supported:
39
+
37
+ return
40
unsigned int write_gen; /* Current data generation */
38
+
41
39
+ not_sup = supported and (imgproto not in supported)
42
/* Protected by reqs_lock. */
40
+ if not_sup or (imgproto in unsupported):
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
41
+ notrun('not suitable for this protocol: %s' % imgproto)
44
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
42
+
45
BdrvRequestFlags flags);
43
def verify_platform(supported_oses=['linux']):
46
44
if True not in [sys.platform.startswith(x) for x in supported_oses]:
47
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent);
45
notrun('not suitable for this OS: %s' % sys.platform)
48
+void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent);
49
+
50
int get_tmp_filename(char *filename, int size);
51
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
52
const char *filename);
53
diff --git a/block.c b/block.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block.c
56
+++ b/block.c
57
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_end(BdrvChild *child)
58
bdrv_drained_end(bs);
59
}
60
61
+static void bdrv_child_cb_attach(BdrvChild *child)
62
+{
63
+ BlockDriverState *bs = child->opaque;
64
+ bdrv_apply_subtree_drain(child, bs);
65
+}
66
+
67
+static void bdrv_child_cb_detach(BdrvChild *child)
68
+{
69
+ BlockDriverState *bs = child->opaque;
70
+ bdrv_unapply_subtree_drain(child, bs);
71
+}
72
+
73
static int bdrv_child_cb_inactivate(BdrvChild *child)
74
{
75
BlockDriverState *bs = child->opaque;
76
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_file = {
77
.inherit_options = bdrv_inherited_options,
78
.drained_begin = bdrv_child_cb_drained_begin,
79
.drained_end = bdrv_child_cb_drained_end,
80
+ .attach = bdrv_child_cb_attach,
81
+ .detach = bdrv_child_cb_detach,
82
.inactivate = bdrv_child_cb_inactivate,
83
};
84
85
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
86
.inherit_options = bdrv_inherited_fmt_options,
87
.drained_begin = bdrv_child_cb_drained_begin,
88
.drained_end = bdrv_child_cb_drained_end,
89
+ .attach = bdrv_child_cb_attach,
90
+ .detach = bdrv_child_cb_detach,
91
.inactivate = bdrv_child_cb_inactivate,
92
};
93
94
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_attach(BdrvChild *c)
95
parent->backing_blocker);
96
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
97
parent->backing_blocker);
98
+
99
+ bdrv_child_cb_attach(c);
100
}
101
102
static void bdrv_backing_detach(BdrvChild *c)
103
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c)
104
bdrv_op_unblock_all(c->bs, parent->backing_blocker);
105
error_free(parent->backing_blocker);
106
parent->backing_blocker = NULL;
107
+
108
+ bdrv_child_cb_detach(c);
109
}
110
111
/*
112
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
113
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
114
}
115
if (old_bs) {
116
+ /* Detach first so that the recursive drain sections coming from @child
117
+ * are already gone and we only end the drain sections that came from
118
+ * elsewhere. */
119
+ if (child->role->detach) {
120
+ child->role->detach(child);
121
+ }
122
if (old_bs->quiesce_counter && child->role->drained_end) {
123
for (i = 0; i < old_bs->quiesce_counter; i++) {
124
child->role->drained_end(child);
125
}
126
}
127
- if (child->role->detach) {
128
- child->role->detach(child);
129
- }
130
QLIST_REMOVE(child, next_parent);
131
}
132
133
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
134
}
135
}
136
137
+ /* Attach only after starting new drained sections, so that recursive
138
+ * drain sections coming from @child don't get an extra .drained_begin
139
+ * callback. */
140
if (child->role->attach) {
141
child->role->attach(child);
142
}
143
diff --git a/block/io.c b/block/io.c
144
index XXXXXXX..XXXXXXX 100644
145
--- a/block/io.c
146
+++ b/block/io.c
147
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
148
assert(data.done);
149
}
150
151
-static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
152
- BdrvChild *parent)
153
+void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
154
+ BdrvChild *parent)
155
{
156
BdrvChild *child, *next;
157
158
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
159
bdrv_drain_recurse(bs);
160
161
if (recursive) {
162
+ bs->recursive_quiesce_counter++;
163
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
164
bdrv_do_drained_begin(child->bs, true, child);
165
}
166
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_begin(BlockDriverState *bs)
167
bdrv_do_drained_begin(bs, true, NULL);
168
}
169
170
-static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
171
- BdrvChild *parent)
172
+void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
173
+ BdrvChild *parent)
174
{
175
BdrvChild *child, *next;
176
int old_quiesce_counter;
177
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
178
}
179
180
if (recursive) {
181
+ bs->recursive_quiesce_counter--;
182
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
183
bdrv_do_drained_end(child->bs, true, child);
184
}
185
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_end(BlockDriverState *bs)
186
bdrv_do_drained_end(bs, true, NULL);
187
}
188
189
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
190
+{
191
+ int i;
192
+
193
+ for (i = 0; i < new_parent->recursive_quiesce_counter; i++) {
194
+ bdrv_do_drained_begin(child->bs, true, child);
195
+ }
196
+}
197
+
198
+void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
199
+{
200
+ int i;
201
+
202
+ for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
203
+ bdrv_do_drained_end(child->bs, true, child);
204
+ }
205
+}
206
+
207
/*
208
* Wait for pending requests to complete on a single BlockDriverState subtree,
209
* and suspend block driver's internal I/O until next request arrives.
46
--
210
--
47
2.13.6
211
2.13.6
48
212
49
213
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
3
tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
4
1 file changed, 80 insertions(+)
1
5
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
7
index XXXXXXX..XXXXXXX 100644
8
--- a/tests/test-bdrv-drain.c
9
+++ b/tests/test-bdrv-drain.c
10
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
11
blk_unref(blk_b);
12
}
13
14
+static void test_graph_change(void)
15
+{
16
+ BlockBackend *blk_a, *blk_b;
17
+ BlockDriverState *bs_a, *bs_b, *backing;
18
+ BDRVTestState *a_s, *b_s, *backing_s;
19
+
20
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
21
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
22
+ &error_abort);
23
+ a_s = bs_a->opaque;
24
+ blk_insert_bs(blk_a, bs_a, &error_abort);
25
+
26
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
27
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
28
+ &error_abort);
29
+ b_s = bs_b->opaque;
30
+ blk_insert_bs(blk_b, bs_b, &error_abort);
31
+
32
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
33
+ backing_s = backing->opaque;
34
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
35
+
36
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
37
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
38
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
39
+ g_assert_cmpint(a_s->drain_count, ==, 0);
40
+ g_assert_cmpint(b_s->drain_count, ==, 0);
41
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
42
+
43
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
44
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
45
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
47
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
48
+
49
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
50
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
51
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
52
+ g_assert_cmpint(backing->quiesce_counter, ==, 5);
53
+ g_assert_cmpint(a_s->drain_count, ==, 5);
54
+ g_assert_cmpint(b_s->drain_count, ==, 5);
55
+ g_assert_cmpint(backing_s->drain_count, ==, 5);
56
+
57
+ bdrv_set_backing_hd(bs_b, NULL, &error_abort);
58
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 3);
59
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
60
+ g_assert_cmpint(backing->quiesce_counter, ==, 3);
61
+ g_assert_cmpint(a_s->drain_count, ==, 3);
62
+ g_assert_cmpint(b_s->drain_count, ==, 2);
63
+ g_assert_cmpint(backing_s->drain_count, ==, 3);
64
+
65
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 5);
69
+ g_assert_cmpint(a_s->drain_count, ==, 5);
70
+ g_assert_cmpint(b_s->drain_count, ==, 5);
71
+ g_assert_cmpint(backing_s->drain_count, ==, 5);
72
+
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
74
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
75
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
76
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
77
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
78
+
79
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
80
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
81
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
82
+ g_assert_cmpint(a_s->drain_count, ==, 0);
83
+ g_assert_cmpint(b_s->drain_count, ==, 0);
84
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
85
+
86
+ bdrv_unref(backing);
87
+ bdrv_unref(bs_a);
88
+ bdrv_unref(bs_b);
89
+ blk_unref(blk_a);
90
+ blk_unref(blk_b);
91
+}
92
+
93
94
typedef struct TestBlockJob {
95
BlockJob common;
96
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
97
98
g_test_add_func("/bdrv-drain/nested", test_nested);
99
g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
100
+ g_test_add_func("/bdrv-drain/graph-change", test_graph_change);
101
102
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
103
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
104
--
105
2.13.6
106
107
diff view generated by jsdifflib
1
This adds a filter function to postprocess 'qemu-img info' input
1
Since commit bde70715, base is the only node that is reopened in
2
(similar to what _img_info does), and an img_info_log() function that
2
commit_start(). This means that the code, which still involves an
3
calls 'qemu-img info' and logs the filtered output.
3
explicit BlockReopenQueue, can now be simplified by using bdrv_reopen().
4
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Fam Zheng <famz@redhat.com>
7
Reviewed-by: Jeff Cody <jcody@redhat.com>
8
---
7
---
9
tests/qemu-iotests/iotests.py | 18 ++++++++++++++++++
8
block/commit.c | 8 +-------
10
1 file changed, 18 insertions(+)
9
1 file changed, 1 insertion(+), 7 deletions(-)
11
10
12
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
11
diff --git a/block/commit.c b/block/commit.c
13
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/iotests.py
13
--- a/block/commit.c
15
+++ b/tests/qemu-iotests/iotests.py
14
+++ b/block/commit.c
16
@@ -XXX,XX +XXX,XX @@ def qemu_img_pipe(*args):
15
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
17
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
16
const char *filter_node_name, Error **errp)
18
return subp.communicate()[0]
17
{
19
18
CommitBlockJob *s;
20
+def img_info_log(filename, filter_path=None):
19
- BlockReopenQueue *reopen_queue = NULL;
21
+ output = qemu_img_pipe('info', '-f', imgfmt, filename)
20
int orig_base_flags;
22
+ if not filter_path:
21
BlockDriverState *iter;
23
+ filter_path = filename
22
BlockDriverState *commit_top_bs = NULL;
24
+ log(filter_img_info(output, filter_path))
23
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
25
+
24
/* convert base to r/w, if necessary */
26
def qemu_io(*args):
25
orig_base_flags = bdrv_get_flags(base);
27
'''Run qemu-io and return the stdout data'''
26
if (!(orig_base_flags & BDRV_O_RDWR)) {
28
args = qemu_io_args + list(args)
27
- reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
29
@@ -XXX,XX +XXX,XX @@ def filter_testfiles(msg):
28
- orig_base_flags | BDRV_O_RDWR);
30
prefix = os.path.join(test_dir, "%s-" % (os.getpid()))
29
- }
31
return msg.replace(prefix, 'TEST_DIR/PID-')
30
-
32
31
- if (reopen_queue) {
33
+def filter_img_info(output, filename):
32
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
34
+ lines = []
33
+ bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
35
+ for line in output.split('\n'):
34
if (local_err != NULL) {
36
+ if 'disk size' in line or 'actual-size' in line:
35
error_propagate(errp, local_err);
37
+ continue
36
goto fail;
38
+ line = line.replace(filename, 'TEST_IMG') \
39
+ .replace(imgfmt, 'IMGFMT')
40
+ line = re.sub('iters: [0-9]+', 'iters: XXX', line)
41
+ line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
42
+ lines.append(line)
43
+ return '\n'.join(lines)
44
+
45
def log(msg, filters=[]):
46
for flt in filters:
47
msg = flt(msg)
48
--
37
--
49
2.13.6
38
2.13.6
50
39
51
40
diff view generated by jsdifflib
1
This adds a helper function that returns a list of QMP events that are
1
The bdrv_reopen*() implementation doesn't like it if the graph is
2
already filtered through filter_qmp_event().
2
changed between queuing nodes for reopen and actually reopening them
3
(one of the reasons is that queuing can be recursive).
4
5
So instead of draining the device only in bdrv_reopen_multiple(),
6
require that callers already drained all affected nodes, and assert this
7
in bdrv_reopen_queue().
3
8
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
11
---
8
tests/qemu-iotests/iotests.py | 5 +++++
12
block.c | 23 ++++++++++++++++-------
9
1 file changed, 5 insertions(+)
13
block/replication.c | 6 ++++++
14
qemu-io-cmds.c | 3 +++
15
3 files changed, 25 insertions(+), 7 deletions(-)
10
16
11
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
17
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/iotests.py
19
--- a/block.c
14
+++ b/tests/qemu-iotests/iotests.py
20
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
21
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
16
output_list += [key + '=' + obj[key]]
22
* returns a pointer to bs_queue, which is either the newly allocated
17
return ','.join(output_list)
23
* bs_queue, or the existing bs_queue being used.
18
24
*
19
+ def get_qmp_events_filtered(self, wait=True):
25
+ * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple().
20
+ result = []
26
*/
21
+ for ev in self.get_qmp_events(wait=wait):
27
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
22
+ result.append(filter_qmp_event(ev))
28
BlockDriverState *bs,
23
+ return result
29
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
24
30
BdrvChild *child;
25
31
QDict *old_options, *explicit_options;
26
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
32
33
+ /* Make sure that the caller remembered to use a drained section. This is
34
+ * important to avoid graph changes between the recursive queuing here and
35
+ * bdrv_reopen_multiple(). */
36
+ assert(bs->quiesce_counter > 0);
37
+
38
if (bs_queue == NULL) {
39
bs_queue = g_new0(BlockReopenQueue, 1);
40
QSIMPLEQ_INIT(bs_queue);
41
@@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
42
* If all devices prepare successfully, then the changes are committed
43
* to all devices.
44
*
45
+ * All affected nodes must be drained between bdrv_reopen_queue() and
46
+ * bdrv_reopen_multiple().
47
*/
48
int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp)
49
{
50
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
51
52
assert(bs_queue != NULL);
53
54
- aio_context_release(ctx);
55
- bdrv_drain_all_begin();
56
- aio_context_acquire(ctx);
57
-
58
QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
59
+ assert(bs_entry->state.bs->quiesce_counter > 0);
60
if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) {
61
error_propagate(errp, local_err);
62
goto cleanup;
63
@@ -XXX,XX +XXX,XX @@ cleanup:
64
}
65
g_free(bs_queue);
66
67
- bdrv_drain_all_end();
68
-
69
return ret;
70
}
71
72
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
73
{
74
int ret = -1;
75
Error *local_err = NULL;
76
- BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
77
+ BlockReopenQueue *queue;
78
79
+ bdrv_subtree_drained_begin(bs);
80
+
81
+ queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
82
ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err);
83
if (local_err != NULL) {
84
error_propagate(errp, local_err);
85
}
86
+
87
+ bdrv_subtree_drained_end(bs);
88
+
89
return ret;
90
}
91
92
diff --git a/block/replication.c b/block/replication.c
93
index XXXXXXX..XXXXXXX 100644
94
--- a/block/replication.c
95
+++ b/block/replication.c
96
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
97
new_secondary_flags = s->orig_secondary_flags;
98
}
99
100
+ bdrv_subtree_drained_begin(s->hidden_disk->bs);
101
+ bdrv_subtree_drained_begin(s->secondary_disk->bs);
102
+
103
if (orig_hidden_flags != new_hidden_flags) {
104
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
105
new_hidden_flags);
106
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
107
reopen_queue, &local_err);
108
error_propagate(errp, local_err);
109
}
110
+
111
+ bdrv_subtree_drained_end(s->hidden_disk->bs);
112
+ bdrv_subtree_drained_end(s->secondary_disk->bs);
113
}
114
115
static void backup_job_cleanup(BlockDriverState *bs)
116
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
117
index XXXXXXX..XXXXXXX 100644
118
--- a/qemu-io-cmds.c
119
+++ b/qemu-io-cmds.c
120
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
121
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
122
qemu_opts_reset(&reopen_opts);
123
124
+ bdrv_subtree_drained_begin(bs);
125
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
126
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
127
+ bdrv_subtree_drained_end(bs);
128
+
129
if (local_err) {
130
error_report_err(local_err);
131
} else {
27
--
132
--
28
2.13.6
133
2.13.6
29
134
30
135
diff view generated by jsdifflib