1
The following changes since commit 63f495beb4007de5444614125fd6fd178ca6e2b1:
1
The following changes since commit 281f327487c9c9b1599f93c589a408bbf4a651b8:
2
2
3
Merge remote-tracking branch 'remotes/kraxel/tags/pull-cve-2017-2620-20170224-1' into staging (2017-02-24 13:55:26 +0000)
3
Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.12-pull-request' into staging (2017-12-22 00:11:36 +0000)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
8
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
9
8
10
for you to fetch changes up to d185cf0ec64cd183218ca7e0810d9130c96ebebc:
9
for you to fetch changes up to 1a63a907507fbbcfaee3f622907ec244b7eabda8:
11
10
12
tests: Use opened block node for block job tests (2017-02-24 16:09:23 +0100)
11
block: Keep nodes drained between reopen_queue/multiple (2017-12-22 15:05:32 +0100)
13
12
14
----------------------------------------------------------------
13
----------------------------------------------------------------
15
Block layer patches
14
Block layer patches
16
15
17
----------------------------------------------------------------
16
----------------------------------------------------------------
18
Jeff Cody (3):
17
Doug Gale (1):
19
qemu-iotests: Test 137 only supports 'file' protocol
18
nvme: Add tracing
20
qemu-iotests: add ability to exclude certain protocols from tests
19
21
qemu-iotests: redirect nbd server stdout to /dev/null
20
Edgar Kaziakhmedov (1):
21
qcow2: get rid of qcow2_backing_read1 routine
22
23
Fam Zheng (2):
24
block: Open backing image in force share mode for size probe
25
block: Remove unused bdrv_requests_pending
22
26
23
John Snow (1):
27
John Snow (1):
24
iotests: Fix another race in 030
28
iotests: fix 197 for vpc
25
29
26
Kevin Wolf (11):
30
Kevin Wolf (27):
27
blockdev: Use BlockBackend to resize in qmp_block_resize()
31
block: Formats don't need CONSISTENT_READ with NO_IO
28
qcow2: Use BB for resizing in qcow2_amend_options()
32
block: Make bdrv_drain_invoke() recursive
29
mirror: Resize active commit base in mirror_run()
33
block: Call .drain_begin only once in bdrv_drain_all_begin()
30
block: Pass BdrvChild to bdrv_truncate()
34
test-bdrv-drain: Test BlockDriver callbacks for drain
31
block: Attach bs->file only during .bdrv_open()
35
block: bdrv_drain_recurse(): Remove unused begin parameter
32
block: Factor out bdrv_open_child_bs()
36
block: Don't wait for requests in bdrv_drain*_end()
33
block: Use BlockBackend for image probing
37
block: Unify order in drain functions
34
block: Factor out bdrv_open_driver()
38
block: Don't acquire AioContext in hmp_qemu_io()
35
block: Add bdrv_new_open_driver()
39
block: Document that x-blockdev-change breaks quorum children list
36
vvfat: Use opened node as backing file
40
block: Assert drain_all is only called from main AioContext
37
tests: Use opened block node for block job tests
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
38
58
39
Nir Soffer (4):
59
Thomas Huth (3):
40
qemu-img: Do not truncate before preallocation
60
block: Remove the obsolete -drive boot=on|off parameter
41
qemu-img: Add tests for raw image preallocation
61
block: Remove the deprecated -hdachs option
42
qemu-img: Truncate before full preallocation
62
block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter
43
qemu-img: Improve documentation for PREALLOC_MODE_FALLOC
44
63
45
block.c | 265 +++++++++++++++++++++++++++---------------
64
qapi/block-core.json | 4 +
46
block/blkdebug.c | 2 +-
65
block/qcow2.h | 3 -
47
block/block-backend.c | 2 +-
66
include/block/block.h | 15 +-
48
block/bochs.c | 6 +
67
include/block/block_int.h | 6 +-
49
block/cloop.c | 6 +
68
block.c | 75 ++++-
50
block/crypto.c | 8 +-
69
block/commit.c | 8 +-
51
block/dmg.c | 6 +
70
block/io.c | 164 +++++++---
52
block/file-posix.c | 28 +++--
71
block/qcow2.c | 51 +--
53
block/mirror.c | 50 ++++----
72
block/replication.c | 6 +
54
block/parallels.c | 14 ++-
73
blockdev.c | 11 -
55
block/qcow.c | 10 +-
74
blockjob.c | 22 +-
56
block/qcow2-refcount.c | 2 +-
75
hmp.c | 6 -
57
block/qcow2.c | 28 ++++-
76
hw/block/nvme.c | 349 +++++++++++++++++----
58
block/qed.c | 18 ++-
77
qemu-io-cmds.c | 3 +
59
block/raw-format.c | 8 +-
78
tests/test-bdrv-drain.c | 651 +++++++++++++++++++++++++++++++++++++++
60
block/replication.c | 6 +
79
vl.c | 86 +-----
61
block/vdi.c | 6 +
80
hw/block/trace-events | 93 ++++++
62
block/vhdx-log.c | 2 +-
81
qemu-doc.texi | 29 +-
63
block/vhdx.c | 8 +-
82
qemu-options.hx | 19 +-
64
block/vmdk.c | 6 +
83
tests/Makefile.include | 2 +
65
block/vpc.c | 6 +
84
tests/qemu-iotests/197 | 4 +
66
block/vvfat.c | 10 +-
85
tests/qemu-iotests/common.filter | 3 +-
67
blockdev.c | 7 +-
86
22 files changed, 1294 insertions(+), 316 deletions(-)
68
include/block/block.h | 4 +-
87
create mode 100644 tests/test-bdrv-drain.c
69
tests/qemu-iotests/030 | 5 +-
70
tests/qemu-iotests/051.out | 4 +-
71
tests/qemu-iotests/051.pc.out | 4 +-
72
tests/qemu-iotests/137 | 2 +-
73
tests/qemu-iotests/175 | 61 ++++++++++
74
tests/qemu-iotests/175.out | 18 +++
75
tests/qemu-iotests/common.rc | 14 ++-
76
tests/qemu-iotests/group | 1 +
77
tests/test-blockjob-txn.c | 6 +-
78
tests/test-blockjob.c | 6 +-
79
34 files changed, 461 insertions(+), 168 deletions(-)
80
create mode 100755 tests/qemu-iotests/175
81
create mode 100644 tests/qemu-iotests/175.out
82
88
diff view generated by jsdifflib
1
This function allows to create more or less normal BlockDriverStates
1
Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently
2
even for BlockDrivers that aren't globally registered (e.g. helper
2
in use as a mirror target. It is not enough for image formats, though,
3
filters for block jobs).
3
as these still unconditionally request BLK_PERM_CONSISTENT_READ.
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.
4
10
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
12
---
8
block.c | 30 +++++++++++++++++++++++++++++-
13
block.c | 6 +++++-
9
include/block/block.h | 2 ++
14
1 file changed, 5 insertions(+), 1 deletion(-)
10
2 files changed, 31 insertions(+), 1 deletion(-)
11
15
12
diff --git a/block.c b/block.c
16
diff --git a/block.c b/block.c
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/block.c
18
--- a/block.c
15
+++ b/block.c
19
+++ b/block.c
16
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
20
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
17
}
21
assert(role == &child_backing || role == &child_file);
18
22
19
bs->drv = drv;
23
if (!backing) {
20
+ bs->read_only = !(bs->open_flags & BDRV_O_RDWR);
24
+ int flags = bdrv_reopen_get_flags(reopen_queue, bs);
21
bs->opaque = g_malloc0(drv->instance_size);
22
23
if (drv->bdrv_file_open) {
24
assert(!drv->bdrv_needs_filename || bs->filename[0]);
25
ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
26
- } else {
27
+ } else if (drv->bdrv_open) {
28
ret = drv->bdrv_open(bs, options, open_flags, &local_err);
29
+ } else {
30
+ ret = 0;
31
}
32
33
if (ret < 0) {
34
@@ -XXX,XX +XXX,XX @@ free_and_fail:
35
return ret;
36
}
37
38
+BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
39
+ int flags, Error **errp)
40
+{
41
+ BlockDriverState *bs;
42
+ int ret;
43
+
25
+
44
+ bs = bdrv_new();
26
/* Apart from the modifications below, the same permissions are
45
+ bs->open_flags = flags;
27
* forwarded and left alone as for filters */
46
+ bs->explicit_options = qdict_new();
28
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
47
+ bs->options = qdict_new();
29
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
48
+ bs->opaque = NULL;
30
49
+
31
/* bs->file always needs to be consistent because of the metadata. We
50
+ update_options_from_flags(bs->options, flags);
32
* can never allow other users to resize or write to it. */
51
+
33
- perm |= BLK_PERM_CONSISTENT_READ;
52
+ ret = bdrv_open_driver(bs, drv, node_name, bs->options, flags, errp);
34
+ if (!(flags & BDRV_O_NO_IO)) {
53
+ if (ret < 0) {
35
+ perm |= BLK_PERM_CONSISTENT_READ;
54
+ QDECREF(bs->explicit_options);
36
+ }
55
+ QDECREF(bs->options);
37
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
56
+ bdrv_unref(bs);
38
} else {
57
+ return NULL;
39
/* We want consistent read from backing files if the parent needs it.
58
+ }
59
+
60
+ return bs;
61
+}
62
+
63
QemuOptsList bdrv_runtime_opts = {
64
.name = "bdrv_common",
65
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
66
diff --git a/include/block/block.h b/include/block/block.h
67
index XXXXXXX..XXXXXXX 100644
68
--- a/include/block/block.h
69
+++ b/include/block/block.h
70
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
71
const char *bdref_key, Error **errp);
72
BlockDriverState *bdrv_open(const char *filename, const char *reference,
73
QDict *options, int flags, Error **errp);
74
+BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
75
+ int flags, Error **errp);
76
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
77
BlockDriverState *bs,
78
QDict *options, int flags);
79
--
40
--
80
1.8.3.1
41
2.13.6
81
42
82
43
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: John Snow <jsnow@redhat.com>
2
2
3
We can't rely on a non-paused job to be present and running for us.
3
VPC has some difficulty creating geometries of particular size.
4
Assume that if the job is not present that it completed already.
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.
5
7
6
Signed-off-by: John Snow <jsnow@redhat.com>
8
Signed-off-by: John Snow <jsnow@redhat.com>
7
Reviewed-by: Fam Zheng <famz@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Lukáš Doktor <ldoktor@redhat.com>
9
---
13
---
10
tests/qemu-iotests/030 | 5 ++++-
14
tests/qemu-iotests/197 | 4 ++++
11
1 file changed, 4 insertions(+), 1 deletion(-)
15
tests/qemu-iotests/common.filter | 3 ++-
16
2 files changed, 6 insertions(+), 1 deletion(-)
12
17
13
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
18
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
14
index XXXXXXX..XXXXXXX 100755
19
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/030
20
--- a/tests/qemu-iotests/197
16
+++ b/tests/qemu-iotests/030
21
+++ b/tests/qemu-iotests/197
17
@@ -XXX,XX +XXX,XX @@ class TestEIO(TestErrors):
22
@@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ==='
18
while not completed:
23
echo
19
for event in self.vm.get_qmp_events(wait=True):
24
20
if event['event'] == 'BLOCK_JOB_ERROR':
25
# Prep the images
21
+ error = True
26
+# VPC rounds image sizes to a specific geometry, force a specific size.
22
self.assert_qmp(event, 'data/device', 'drive0')
27
+if [ "$IMGFMT" = "vpc" ]; then
23
self.assert_qmp(event, 'data/operation', 'read')
28
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
24
result = self.vm.qmp('query-block-jobs')
29
+fi
25
+ if result == {'return': []}:
30
_make_test_img 4G
26
+ # Job finished too quickly
31
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
27
+ continue
32
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
28
self.assert_qmp(result, 'return[0]/paused', False)
33
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
29
- error = True
34
index XXXXXXX..XXXXXXX 100644
30
elif event['event'] == 'BLOCK_JOB_COMPLETED':
35
--- a/tests/qemu-iotests/common.filter
31
self.assertTrue(error, 'job completed unexpectedly')
36
+++ b/tests/qemu-iotests/common.filter
32
self.assert_qmp(event, 'data/type', 'stream')
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()
33
--
47
--
34
1.8.3.1
48
2.13.6
35
49
36
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
1
From: Nir Soffer <nirsof@gmail.com>
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.
2
4
3
Add tests for creating raw image with and without the preallocation
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
option.
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
5
13
6
Signed-off-by: Nir Soffer <nirsof@gmail.com>
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
tests/qemu-iotests/175 | 61 ++++++++++++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/175.out | 18 ++++++++++++++
11
tests/qemu-iotests/group | 1 +
12
3 files changed, 80 insertions(+)
13
create mode 100755 tests/qemu-iotests/175
14
create mode 100644 tests/qemu-iotests/175.out
15
16
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
17
new file mode 100755
18
index XXXXXXX..XXXXXXX
19
--- /dev/null
20
+++ b/tests/qemu-iotests/175
21
@@ -XXX,XX +XXX,XX @@
22
+#!/bin/bash
23
+#
24
+# Test creating raw image preallocation mode
25
+#
26
+# Copyright (C) 2017 Nir Soffer <nirsof@gmail.com>
27
+#
28
+# This program is free software; you can redistribute it and/or modify
29
+# it under the terms of the GNU General Public License as published by
30
+# the Free Software Foundation; either version 2 of the License, or
31
+# (at your option) any later version.
32
+#
33
+# This program is distributed in the hope that it will be useful,
34
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
35
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36
+# GNU General Public License for more details.
37
+#
38
+# You should have received a copy of the GNU General Public License
39
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
40
+#
41
+
42
+# creator
43
+owner=nirsof@gmail.com
44
+
45
+seq=`basename $0`
46
+echo "QA output created by $seq"
47
+
48
+here=`pwd`
49
+status=1    # failure is the default!
50
+
51
+_cleanup()
52
+{
53
+    _cleanup_test_img
54
+}
55
+trap "_cleanup; exit \$status" 0 1 2 3 15
56
+
57
+# get standard environment, filters and checks
58
+. ./common.rc
59
+. ./common.filter
60
+
61
+_supported_fmt raw
62
+_supported_proto file
63
+_supported_os Linux
64
+
65
+size=1m
66
+
67
+echo
68
+echo "== creating image with default preallocation =="
69
+_make_test_img $size | _filter_imgfmt
70
+stat -c "size=%s, blocks=%b" $TEST_IMG
71
+
72
+for mode in off full falloc; do
73
+ echo
74
+ echo "== creating image with preallocation $mode =="
75
+ IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
76
+ stat -c "size=%s, blocks=%b" $TEST_IMG
77
+done
78
+
79
+# success, all done
80
+echo "*** done"
81
+rm -f $seq.full
82
+status=0
83
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
84
new file mode 100644
15
new file mode 100644
85
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
86
--- /dev/null
17
--- /dev/null
87
+++ b/tests/qemu-iotests/175.out
18
+++ b/tests/test-bdrv-drain.c
88
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
89
+QA output created by 175
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
+ */
90
+
43
+
91
+== creating image with default preallocation ==
44
+#include "qemu/osdep.h"
92
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
45
+#include "block/block.h"
93
+size=1048576, blocks=0
46
+#include "sysemu/block-backend.h"
47
+#include "qapi/error.h"
94
+
48
+
95
+== creating image with preallocation off ==
49
+typedef struct BDRVTestState {
96
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off
50
+ int drain_count;
97
+size=1048576, blocks=0
51
+} BDRVTestState;
98
+
52
+
99
+== creating image with preallocation full ==
53
+static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
100
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full
54
+{
101
+size=1048576, blocks=2048
55
+ BDRVTestState *s = bs->opaque;
56
+ s->drain_count++;
57
+}
102
+
58
+
103
+== creating image with preallocation falloc ==
59
+static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
104
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
60
+{
105
+size=1048576, blocks=2048
61
+ BDRVTestState *s = bs->opaque;
106
+ *** done
62
+ s->drain_count--;
107
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
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
108
index XXXXXXX..XXXXXXX 100644
158
index XXXXXXX..XXXXXXX 100644
109
--- a/tests/qemu-iotests/group
159
--- a/tests/Makefile.include
110
+++ b/tests/qemu-iotests/group
160
+++ b/tests/Makefile.include
111
@@ -XXX,XX +XXX,XX @@
161
@@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c
112
172 auto
162
gcov-files-test-hbitmap-y = util/hbitmap.c
113
173 rw auto
163
check-unit-y += tests/test-hbitmap$(EXESUF)
114
174 auto
164
gcov-files-test-hbitmap-y = blockjob.c
115
+175 auto quick
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)
116
--
177
--
117
1.8.3.1
178
2.13.6
118
179
119
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
New patch
1
The device is drained, so there is no point in waiting for requests at
2
the end of the drained section. Remove the bdrv_drain_recurse() calls
3
there.
1
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.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
block/io.c | 2 --
14
1 file changed, 2 deletions(-)
15
16
diff --git a/block/io.c b/block/io.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/io.c
19
+++ b/block/io.c
20
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
21
22
bdrv_parent_drained_end(bs);
23
bdrv_drain_invoke(bs, false);
24
- bdrv_drain_recurse(bs);
25
aio_enable_external(bdrv_get_aio_context(bs));
26
}
27
28
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
29
aio_enable_external(aio_context);
30
bdrv_parent_drained_end(bs);
31
bdrv_drain_invoke(bs, false);
32
- bdrv_drain_recurse(bs);
33
aio_context_release(aio_context);
34
}
35
36
--
37
2.13.6
38
39
diff view generated by jsdifflib
1
This is more consistent with the commit block job, and it moves the code
1
Drain requests are propagated to child nodes, parent nodes and directly
2
to a place where we already have the necessary BlockBackends to resize
2
to the AioContext. The order in which this happened was different
3
the base image when bdrv_truncate() is changed to require a BdrvChild.
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.
4
13
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
16
---
8
block/mirror.c | 50 ++++++++++++++++++++++----------------------------
17
block/io.c | 12 ++++++++----
9
1 file changed, 22 insertions(+), 28 deletions(-)
18
1 file changed, 8 insertions(+), 4 deletions(-)
10
19
11
diff --git a/block/mirror.c b/block/mirror.c
20
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
13
--- a/block/mirror.c
22
--- a/block/io.c
14
+++ b/block/mirror.c
23
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
24
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
16
if (s->bdev_length < 0) {
17
ret = s->bdev_length;
18
goto immediate_exit;
19
- } else if (s->bdev_length == 0) {
20
+ }
21
+
22
+ /* Active commit must resize the base image if its size differs from the
23
+ * active layer. */
24
+ if (s->base == blk_bs(s->target)) {
25
+ int64_t base_length;
26
+
27
+ base_length = blk_getlength(s->target);
28
+ if (base_length < 0) {
29
+ ret = base_length;
30
+ goto immediate_exit;
31
+ }
32
+
33
+ if (s->bdev_length > base_length) {
34
+ ret = blk_truncate(s->target, s->bdev_length);
35
+ if (ret < 0) {
36
+ goto immediate_exit;
37
+ }
38
+ }
39
+ }
40
+
41
+ if (s->bdev_length == 0) {
42
/* Report BLOCK_JOB_READY and wait for complete. */
43
block_job_event_ready(&s->common);
44
s->synced = true;
45
@@ -XXX,XX +XXX,XX @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
46
BlockCompletionFunc *cb, void *opaque, Error **errp,
47
bool auto_complete)
48
{
49
- int64_t length, base_length;
50
int orig_base_flags;
51
- int ret;
52
Error *local_err = NULL;
53
54
orig_base_flags = bdrv_get_flags(base);
55
@@ -XXX,XX +XXX,XX @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
56
return;
25
return;
57
}
26
}
58
27
59
- length = bdrv_getlength(bs);
28
+ /* Stop things in parent-to-child order */
60
- if (length < 0) {
29
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
61
- error_setg_errno(errp, -length,
30
aio_disable_external(bdrv_get_aio_context(bs));
62
- "Unable to determine length of %s", bs->filename);
31
bdrv_parent_drained_begin(bs);
63
- goto error_restore_flags;
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
64
- }
33
return;
65
-
34
}
66
- base_length = bdrv_getlength(base);
35
67
- if (base_length < 0) {
36
- bdrv_parent_drained_end(bs);
68
- error_setg_errno(errp, -base_length,
37
+ /* Re-enable things in child-to-parent order */
69
- "Unable to determine length of %s", base->filename);
38
bdrv_drain_invoke(bs, false);
70
- goto error_restore_flags;
39
+ bdrv_parent_drained_end(bs);
71
- }
40
aio_enable_external(bdrv_get_aio_context(bs));
72
-
41
}
73
- if (length > base_length) {
42
74
- ret = bdrv_truncate(base, length);
43
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
75
- if (ret < 0) {
44
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
76
- error_setg_errno(errp, -ret,
45
AioContext *aio_context = bdrv_get_aio_context(bs);
77
- "Top image %s is larger than base image %s, and "
46
78
- "resize of base image failed",
47
+ /* Stop things in parent-to-child order */
79
- bs->filename, base->filename);
48
aio_context_acquire(aio_context);
80
- goto error_restore_flags;
49
- bdrv_parent_drained_begin(bs);
81
- }
50
aio_disable_external(aio_context);
82
- }
51
+ bdrv_parent_drained_begin(bs);
83
-
52
bdrv_drain_invoke(bs, true);
84
mirror_start_job(job_id, bs, creation_flags, base, NULL, speed, 0, 0,
53
aio_context_release(aio_context);
85
MIRROR_LEAVE_BACKING_CHAIN,
54
86
on_error, on_error, true, cb, opaque, &local_err,
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
}
68
87
--
69
--
88
1.8.3.1
70
2.13.6
89
71
90
72
diff view generated by jsdifflib
1
In order to able to convert bdrv_truncate() to take a BdrvChild and
1
Commit 15afd94a047 added code to acquire and release the AioContext in
2
later to correctly check the resize permission here, we need to use a
2
qemuio_command(). This means that the lock is taken twice now in the
3
BlockBackend for resizing the image.
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.
4
7
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
10
---
8
block/qcow2.c | 6 +++++-
11
hmp.c | 6 ------
9
1 file changed, 5 insertions(+), 1 deletion(-)
12
1 file changed, 6 deletions(-)
10
13
11
diff --git a/block/qcow2.c b/block/qcow2.c
14
diff --git a/hmp.c b/hmp.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qcow2.c
16
--- a/hmp.c
14
+++ b/block/qcow2.c
17
+++ b/hmp.c
15
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
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)
27
}
16
}
28
}
17
29
18
if (new_size) {
30
- aio_context = blk_get_aio_context(blk);
19
- ret = bdrv_truncate(bs, new_size);
31
- aio_context_acquire(aio_context);
20
+ BlockBackend *blk = blk_new();
32
-
21
+ blk_insert_bs(blk, bs);
33
/*
22
+ ret = blk_truncate(blk, new_size);
34
* Notably absent: Proper permission management. This is sad, but it seems
23
+ blk_unref(blk);
35
* almost impossible to achieve without changing the semantics and thereby
24
+
36
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
25
if (ret < 0) {
37
*/
26
return ret;
38
qemuio_command(blk, command);
27
}
39
40
- aio_context_release(aio_context);
41
-
42
fail:
43
blk_unref(local_blk);
44
hmp_handle_error(mon, &err);
28
--
45
--
29
1.8.3.1
46
2.13.6
30
47
31
48
diff view generated by jsdifflib
1
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
2
3
Since bdrv_co_preadv does all neccessary checks including
4
reading after the end of the backing file, avoid duplication
5
of verification before bdrv_co_preadv call.
6
7
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
---
11
---
4
block.c | 3 ++-
12
block/qcow2.h | 3 ---
5
block/blkdebug.c | 2 +-
13
block/qcow2.c | 51 ++++++++-------------------------------------------
6
block/block-backend.c | 2 +-
14
2 files changed, 8 insertions(+), 46 deletions(-)
7
block/crypto.c | 2 +-
8
block/parallels.c | 8 ++++----
9
block/qcow.c | 4 ++--
10
block/qcow2-refcount.c | 2 +-
11
block/qcow2.c | 4 ++--
12
block/raw-format.c | 2 +-
13
block/vhdx-log.c | 2 +-
14
block/vhdx.c | 2 +-
15
include/block/block.h | 2 +-
16
12 files changed, 18 insertions(+), 17 deletions(-)
17
15
18
diff --git a/block.c b/block.c
16
diff --git a/block/qcow2.h b/block/qcow2.h
19
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
20
--- a/block.c
18
--- a/block/qcow2.h
21
+++ b/block.c
19
+++ b/block/qcow2.h
22
@@ -XXX,XX +XXX,XX @@ exit:
20
@@ -XXX,XX +XXX,XX @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
23
/**
24
* Truncate file to 'offset' bytes (needed only for file protocols)
25
*/
26
-int bdrv_truncate(BlockDriverState *bs, int64_t offset)
27
+int bdrv_truncate(BdrvChild *child, int64_t offset)
28
{
29
+ BlockDriverState *bs = child->bs;
30
BlockDriver *drv = bs->drv;
31
int ret;
32
if (!drv)
33
diff --git a/block/blkdebug.c b/block/blkdebug.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/block/blkdebug.c
36
+++ b/block/blkdebug.c
37
@@ -XXX,XX +XXX,XX @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
38
39
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
40
{
41
- return bdrv_truncate(bs->file->bs, offset);
42
+ return bdrv_truncate(bs->file, offset);
43
}
21
}
44
22
45
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
23
/* qcow2.c functions */
46
diff --git a/block/block-backend.c b/block/block-backend.c
24
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
47
index XXXXXXX..XXXXXXX 100644
25
- int64_t sector_num, int nb_sectors);
48
--- a/block/block-backend.c
26
-
49
+++ b/block/block-backend.c
27
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
50
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset)
28
int refcount_order, bool generous_increase,
51
return -ENOMEDIUM;
29
uint64_t *refblock_count);
52
}
53
54
- return bdrv_truncate(blk_bs(blk), offset);
55
+ return bdrv_truncate(blk->root, offset);
56
}
57
58
static void blk_pdiscard_entry(void *opaque)
59
diff --git a/block/crypto.c b/block/crypto.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block/crypto.c
62
+++ b/block/crypto.c
63
@@ -XXX,XX +XXX,XX @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
64
65
offset += payload_offset;
66
67
- return bdrv_truncate(bs->file->bs, offset);
68
+ return bdrv_truncate(bs->file, offset);
69
}
70
71
static void block_crypto_close(BlockDriverState *bs)
72
diff --git a/block/parallels.c b/block/parallels.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/block/parallels.c
75
+++ b/block/parallels.c
76
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
77
s->data_end << BDRV_SECTOR_BITS,
78
space << BDRV_SECTOR_BITS, 0);
79
} else {
80
- ret = bdrv_truncate(bs->file->bs,
81
+ ret = bdrv_truncate(bs->file,
82
(s->data_end + space) << BDRV_SECTOR_BITS);
83
}
84
if (ret < 0) {
85
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
86
size - res->image_end_offset);
87
res->leaks += count;
88
if (fix & BDRV_FIX_LEAKS) {
89
- ret = bdrv_truncate(bs->file->bs, res->image_end_offset);
90
+ ret = bdrv_truncate(bs->file, res->image_end_offset);
91
if (ret < 0) {
92
res->check_errors++;
93
return ret;
94
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
95
goto fail_options;
96
}
97
if (!bdrv_has_zero_init(bs->file->bs) ||
98
- bdrv_truncate(bs->file->bs, bdrv_getlength(bs->file->bs)) != 0) {
99
+ bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs)) != 0) {
100
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
101
}
102
103
@@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs)
104
}
105
106
if (bs->open_flags & BDRV_O_RDWR) {
107
- bdrv_truncate(bs->file->bs, s->data_end << BDRV_SECTOR_BITS);
108
+ bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS);
109
}
110
111
g_free(s->bat_dirty_bmap);
112
diff --git a/block/qcow.c b/block/qcow.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/qcow.c
115
+++ b/block/qcow.c
116
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
117
/* round to cluster size */
118
cluster_offset = (cluster_offset + s->cluster_size - 1) &
119
~(s->cluster_size - 1);
120
- bdrv_truncate(bs->file->bs, cluster_offset + s->cluster_size);
121
+ bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
122
/* if encrypted, we must initialize the cluster
123
content which won't be written */
124
if (bs->encrypted &&
125
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
126
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
127
l1_length) < 0)
128
return -1;
129
- ret = bdrv_truncate(bs->file->bs, s->l1_table_offset + l1_length);
130
+ ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
131
if (ret < 0)
132
return ret;
133
134
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
135
index XXXXXXX..XXXXXXX 100644
136
--- a/block/qcow2-refcount.c
137
+++ b/block/qcow2-refcount.c
138
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
139
goto resize_fail;
140
}
141
142
- ret = bdrv_truncate(bs->file->bs, offset + s->cluster_size);
143
+ ret = bdrv_truncate(bs->file, offset + s->cluster_size);
144
if (ret < 0) {
145
goto resize_fail;
146
}
147
diff --git a/block/qcow2.c b/block/qcow2.c
30
diff --git a/block/qcow2.c b/block/qcow2.c
148
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
149
--- a/block/qcow2.c
32
--- a/block/qcow2.c
150
+++ b/block/qcow2.c
33
+++ b/block/qcow2.c
151
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
34
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
152
/* align end of file to a sector boundary to ease reading with
35
return status;
153
sector based I/Os */
154
cluster_offset = bdrv_getlength(bs->file->bs);
155
- return bdrv_truncate(bs->file->bs, cluster_offset);
156
+ return bdrv_truncate(bs->file, cluster_offset);
157
}
158
159
buf = qemu_blockalign(bs, s->cluster_size);
160
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
161
goto fail;
162
}
163
164
- ret = bdrv_truncate(bs->file->bs, (3 + l1_clusters) * s->cluster_size);
165
+ ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size);
166
if (ret < 0) {
167
goto fail;
168
}
169
diff --git a/block/raw-format.c b/block/raw-format.c
170
index XXXXXXX..XXXXXXX 100644
171
--- a/block/raw-format.c
172
+++ b/block/raw-format.c
173
@@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset)
174
175
s->size = offset;
176
offset += s->offset;
177
- return bdrv_truncate(bs->file->bs, offset);
178
+ return bdrv_truncate(bs->file, offset);
179
}
36
}
180
37
181
static int raw_media_changed(BlockDriverState *bs)
38
-/* handle reading after the end of the backing file */
182
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
39
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
183
index XXXXXXX..XXXXXXX 100644
40
- int64_t offset, int bytes)
184
--- a/block/vhdx-log.c
41
-{
185
+++ b/block/vhdx-log.c
42
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
186
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
43
- int n1;
187
if (new_file_size % (1024*1024)) {
44
-
188
/* round up to nearest 1MB boundary */
45
- if ((offset + bytes) <= bs_size) {
189
new_file_size = ((new_file_size >> 20) + 1) << 20;
46
- return bytes;
190
- bdrv_truncate(bs->file->bs, new_file_size);
47
- }
191
+ bdrv_truncate(bs->file, new_file_size);
48
-
192
}
49
- if (offset >= bs_size) {
193
}
50
- n1 = 0;
194
qemu_vfree(desc_entries);
51
- } else {
195
diff --git a/block/vhdx.c b/block/vhdx.c
52
- n1 = bs_size - offset;
196
index XXXXXXX..XXXXXXX 100644
53
- }
197
--- a/block/vhdx.c
54
-
198
+++ b/block/vhdx.c
55
- qemu_iovec_memset(qiov, n1, 0, bytes - n1);
199
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
56
-
200
/* per the spec, the address for a block is in units of 1MB */
57
- return n1;
201
*new_offset = ROUND_UP(*new_offset, 1024 * 1024);
58
-}
202
59
-
203
- return bdrv_truncate(bs->file->bs, *new_offset + s->block_size);
60
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
204
+ return bdrv_truncate(bs->file, *new_offset + s->block_size);
61
uint64_t bytes, QEMUIOVector *qiov,
205
}
62
int flags)
206
63
{
207
/*
64
BDRVQcow2State *s = bs->opaque;
208
diff --git a/include/block/block.h b/include/block/block.h
65
- int offset_in_cluster, n1;
209
index XXXXXXX..XXXXXXX 100644
66
+ int offset_in_cluster;
210
--- a/include/block/block.h
67
int ret;
211
+++ b/include/block/block.h
68
unsigned int cur_bytes; /* number of bytes in current iteration */
212
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
69
uint64_t cluster_offset = 0;
213
const char *backing_file);
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
214
int bdrv_get_backing_file_depth(BlockDriverState *bs);
71
case QCOW2_CLUSTER_UNALLOCATED:
215
void bdrv_refresh_filename(BlockDriverState *bs);
72
216
-int bdrv_truncate(BlockDriverState *bs, int64_t offset);
73
if (bs->backing) {
217
+int bdrv_truncate(BdrvChild *child, int64_t offset);
74
- /* read from the base image */
218
int64_t bdrv_nb_sectors(BlockDriverState *bs);
75
- n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
219
int64_t bdrv_getlength(BlockDriverState *bs);
76
- offset, cur_bytes);
220
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
77
- if (n1 > 0) {
78
- QEMUIOVector local_qiov;
79
-
80
- qemu_iovec_init(&local_qiov, hd_qiov.niov);
81
- qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1);
82
-
83
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
84
- qemu_co_mutex_unlock(&s->lock);
85
- ret = bdrv_co_preadv(bs->backing, offset, n1,
86
- &local_qiov, 0);
87
- qemu_co_mutex_lock(&s->lock);
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 */
221
--
104
--
222
1.8.3.1
105
2.13.6
223
106
224
107
diff view generated by jsdifflib
New patch
1
Removing a quorum child node with x-blockdev-change results in a quorum
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().
1
5
6
Document this problem so that we won't accidentally mark the command
7
stable without having addressed it.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
---
12
qapi/block-core.json | 4 ++++
13
1 file changed, 4 insertions(+)
14
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
18
+++ b/qapi/block-core.json
19
@@ -XXX,XX +XXX,XX @@
20
# does not support all kinds of operations, all kinds of children, nor
21
# all block drivers.
22
#
23
+# FIXME Removing children from a quorum node means introducing gaps in the
24
+# child indices. This cannot be represented in the 'children' list of
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.
29
#
30
--
31
2.13.6
32
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
1
This fixes the use of a parent-less BdrvChild in bdrv_open_inherit() by
1
From: Fam Zheng <famz@redhat.com>
2
converting it into a BlockBackend. Which is exactly what it should be,
3
image probing is an external, standalone user of a node. The requests
4
can't be considered to originate from the format driver node because
5
that one isn't even opened yet.
6
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>
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
---
18
---
10
block.c | 36 +++++++++++++++++++-----------------
19
block.c | 3 ++-
11
1 file changed, 19 insertions(+), 17 deletions(-)
20
1 file changed, 2 insertions(+), 1 deletion(-)
12
21
13
diff --git a/block.c b/block.c
22
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
24
--- a/block.c
16
+++ b/block.c
25
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
26
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
18
return drv;
27
back_flags = flags;
19
}
28
back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
20
29
21
-static int find_image_format(BdrvChild *file, const char *filename,
30
+ backing_options = qdict_new();
22
+static int find_image_format(BlockBackend *file, const char *filename,
31
if (backing_fmt) {
23
BlockDriver **pdrv, Error **errp)
32
- backing_options = qdict_new();
24
{
33
qdict_put_str(backing_options, "driver", backing_fmt);
25
- BlockDriverState *bs = file->bs;
26
BlockDriver *drv;
27
uint8_t buf[BLOCK_PROBE_BUF_SIZE];
28
int ret = 0;
29
30
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
31
- if (bdrv_is_sg(bs) || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
32
+ if (blk_is_sg(file) || !blk_is_inserted(file) || blk_getlength(file) == 0) {
33
*pdrv = &bdrv_raw;
34
return ret;
35
}
36
37
- ret = bdrv_pread(file, 0, buf, sizeof(buf));
38
+ ret = blk_pread(file, 0, buf, sizeof(buf));
39
if (ret < 0) {
40
error_setg_errno(errp, -ret, "Could not read image for determining its "
41
"format");
42
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
43
*
44
* Removes all processed options from *options.
45
*/
46
-static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
47
+static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
48
QDict *options, Error **errp)
49
{
50
int ret, open_flags;
51
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
52
assert(drv != NULL);
53
54
if (file != NULL) {
55
- filename = file->bs->filename;
56
+ filename = blk_bs(file)->filename;
57
} else {
58
filename = qdict_get_try_str(options, "filename");
59
}
60
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
61
Error **errp)
62
{
63
int ret;
64
- BdrvChild *file = NULL;
65
+ BlockBackend *file = NULL;
66
BlockDriverState *bs;
67
BlockDriver *drv = NULL;
68
const char *drvname;
69
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
70
qdict_del(options, "backing");
71
}
72
73
- /* Open image file without format layer. This BdrvChild is only used for
74
+ /* Open image file without format layer. This BlockBackend is only used for
75
* probing, the block drivers will do their own bdrv_open_child() for the
76
* same BDS, which is why we put the node name back into options. */
77
if ((flags & BDRV_O_PROTOCOL) == 0) {
78
- /* FIXME Shouldn't attach a child to a node that isn't opened yet. */
79
- file = bdrv_open_child(filename, options, "file", bs,
80
- &child_file, true, &local_err);
81
+ BlockDriverState *file_bs;
82
+
83
+ file_bs = bdrv_open_child_bs(filename, options, "file", bs,
84
+ &child_file, true, &local_err);
85
if (local_err) {
86
goto fail;
87
}
34
}
88
- if (file != NULL) {
35
+ qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true);
89
+ if (file_bs != NULL) {
36
90
+ file = blk_new();
37
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
91
+ blk_insert_bs(file, file_bs);
38
&local_err);
92
+ bdrv_unref(file_bs);
93
+
94
qdict_put(options, "file",
95
- qstring_from_str(bdrv_get_node_name(file->bs)));
96
+ qstring_from_str(bdrv_get_node_name(file_bs)));
97
}
98
}
99
100
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
101
}
102
103
if (file) {
104
- bdrv_unref_child(bs, file);
105
+ blk_unref(file);
106
file = NULL;
107
}
108
109
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
110
return bs;
111
112
fail:
113
- if (file != NULL) {
114
- bdrv_unref_child(bs, file);
115
- }
116
+ blk_unref(file);
117
if (bs->file != NULL) {
118
bdrv_unref_child(bs, bs->file);
119
}
120
--
39
--
121
1.8.3.1
40
2.13.6
122
41
123
42
diff view generated by jsdifflib
1
In order to be able to do permission checking and to keep working with
1
From: Thomas Huth <thuth@redhat.com>
2
the BdrvChild based bdrv_truncate() that this involves, we need to
3
create a temporary BlockBackend to resize the image.
4
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>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
9
---
8
blockdev.c | 7 ++++++-
10
blockdev.c | 11 -----------
9
1 file changed, 6 insertions(+), 1 deletion(-)
11
qemu-doc.texi | 6 ------
12
2 files changed, 17 deletions(-)
10
13
11
diff --git a/blockdev.c b/blockdev.c
14
diff --git a/blockdev.c b/blockdev.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/blockdev.c
16
--- a/blockdev.c
14
+++ b/blockdev.c
17
+++ b/blockdev.c
15
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
18
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
16
int64_t size, Error **errp)
19
.type = QEMU_OPT_STRING,
17
{
20
.help = "chs translation (auto, lba, none)",
18
Error *local_err = NULL;
21
},{
19
+ BlockBackend *blk = NULL;
22
- .name = "boot",
20
BlockDriverState *bs;
23
- .type = QEMU_OPT_BOOL,
21
AioContext *aio_context;
24
- .help = "(deprecated, ignored)",
22
int ret;
25
- },{
23
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
26
.name = "addr",
24
goto out;
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;
25
}
31
}
26
32
27
+ blk = blk_new();
33
- /* Deprecated option boot=[on|off] */
28
+ blk_insert_bs(blk, bs);
34
- if (qemu_opt_get(legacy_opts, "boot") != NULL) {
29
+
35
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
30
/* complete all in-flight operations before resizing the device */
36
- "ignored. Future versions will reject this parameter. Please "
31
bdrv_drain_all();
37
- "update your scripts.\n");
32
38
- }
33
- ret = bdrv_truncate(bs, size);
39
-
34
+ ret = blk_truncate(blk, size);
40
/* Other deprecated options */
35
switch (ret) {
41
if (!qtest_enabled()) {
36
case 0:
42
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
37
break;
43
diff --git a/qemu-doc.texi b/qemu-doc.texi
38
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
44
index XXXXXXX..XXXXXXX 100644
39
}
45
--- a/qemu-doc.texi
40
46
+++ b/qemu-doc.texi
41
out:
47
@@ -XXX,XX +XXX,XX @@ deprecated.
42
+ blk_unref(blk);
48
43
aio_context_release(aio_context);
49
@section System emulator command line arguments
44
}
50
45
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
46
--
60
--
47
1.8.3.1
61
2.13.6
48
62
49
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
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
When using file system that does not support fallocate() (e.g. NFS <
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
4.2), truncating the file only when preallocation=OFF speeds up creating
5
raw file.
6
7
Here is example run, tested on Fedora 24 machine, creating raw file on
8
NFS version 3 server.
9
10
$ time ./qemu-img-master create -f raw -o preallocation=falloc mnt/test 1g
11
Formatting 'mnt/test', fmt=raw size=1073741824 preallocation=falloc
12
13
real    0m21.185s
14
user    0m0.022s
15
sys    0m0.574s
16
17
$ time ./qemu-img-fix create -f raw -o preallocation=falloc mnt/test 1g
18
Formatting 'mnt/test', fmt=raw size=1073741824 preallocation=falloc
19
20
real    0m11.601s
21
user    0m0.016s
22
sys    0m0.525s
23
24
$ time dd if=/dev/zero of=mnt/test bs=1M count=1024 oflag=direct
25
1024+0 records in
26
1024+0 records out
27
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 15.6627 s, 68.6 MB/s
28
29
real    0m16.104s
30
user    0m0.009s
31
sys    0m0.220s
32
33
Running with strace we can see that without this change we do one
34
pread() and one pwrite() for each block. With this change, we do only
35
one pwrite() per block.
36
37
$ strace ./qemu-img-master create -f raw -o preallocation=falloc mnt/test 8192
38
...
39
pread64(9, "\0", 1, 4095) = 1
40
pwrite64(9, "\0", 1, 4095) = 1
41
pread64(9, "\0", 1, 8191) = 1
42
pwrite64(9, "\0", 1, 8191) = 1
43
44
$ strace ./qemu-img-fix create -f raw -o preallocation=falloc mnt/test 8192
45
...
46
pwrite64(9, "\0", 1, 4095) = 1
47
pwrite64(9, "\0", 1, 8191) = 1
48
49
This happens because posix_fallocate is checking if each block is
50
allocated before writing a byte to the block, and when truncating the
51
file before preallocation, all blocks are unallocated.
52
53
Signed-off-by: Nir Soffer <nirsof@gmail.com>
54
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
55
---
5
---
56
block/file-posix.c | 11 ++++-------
6
include/block/block_int.h | 1 -
57
1 file changed, 4 insertions(+), 7 deletions(-)
7
block/io.c | 18 ------------------
8
2 files changed, 19 deletions(-)
58
9
59
diff --git a/block/file-posix.c b/block/file-posix.c
10
diff --git a/include/block/block_int.h b/include/block/block_int.h
60
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
61
--- a/block/file-posix.c
12
--- a/include/block/block_int.h
62
+++ b/block/file-posix.c
13
+++ b/include/block/block_int.h
63
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
14
@@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk);
64
#endif
15
bool blk_dev_is_medium_locked(BlockBackend *blk);
65
}
16
66
17
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
67
- if (ftruncate(fd, total_size) != 0) {
18
-bool bdrv_requests_pending(BlockDriverState *bs);
68
- result = -errno;
19
69
- error_setg_errno(errp, -result, "Could not resize file");
20
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
70
- goto out_close;
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;
71
- }
37
- }
72
-
38
-
73
switch (prealloc) {
39
- QLIST_FOREACH(child, &bs->children, next) {
74
#ifdef CONFIG_POSIX_FALLOCATE
40
- if (bdrv_requests_pending(child->bs)) {
75
case PREALLOC_MODE_FALLOC:
41
- return true;
76
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
42
- }
77
break;
43
- }
78
}
44
-
79
case PREALLOC_MODE_OFF:
45
- return false;
80
+ if (ftruncate(fd, total_size) != 0) {
46
-}
81
+ result = -errno;
47
-
82
+ error_setg_errno(errp, -result, "Could not resize file");
48
typedef struct {
83
+ }
49
Coroutine *co;
84
break;
50
BlockDriverState *bs;
85
default:
86
result = -EINVAL;
87
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
88
break;
89
}
90
91
-out_close:
92
if (qemu_close(fd) != 0 && result == 0) {
93
result = -errno;
94
error_setg_errno(errp, -result, "Could not close the new file");
95
--
51
--
96
1.8.3.1
52
2.13.6
97
53
98
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
1
blk_insert_bs() and block job related functions will soon require an
1
This is currently only working correctly for bdrv_drain(), not for
2
opened block node (permission calculations will involve the block
2
bdrv_drain_all(). Leave a comment for the drain_all case, we'll address
3
driver), so let our tests be consistent with the real users in this
3
it later.
4
respect.
5
4
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
6
---
9
tests/test-blockjob-txn.c | 6 +++++-
7
tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
10
tests/test-blockjob.c | 6 +++++-
8
1 file changed, 45 insertions(+)
11
2 files changed, 10 insertions(+), 2 deletions(-)
12
9
13
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/test-blockjob-txn.c
12
--- a/tests/test-bdrv-drain.c
16
+++ b/tests/test-blockjob-txn.c
13
+++ b/tests/test-bdrv-drain.c
17
@@ -XXX,XX +XXX,XX @@ static BlockJob *test_block_job_start(unsigned int iterations,
14
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
18
char job_id[24];
15
test_drv_cb_common(BDRV_DRAIN, false);
19
16
}
20
data = g_new0(TestBlockJobCBData, 1);
17
21
- bs = bdrv_new();
18
+static void test_quiesce_common(enum drain_type drain_type, bool recursive)
19
+{
20
+ BlockBackend *blk;
21
+ BlockDriverState *bs, *backing;
22
+
22
+
23
+ bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
23
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
24
+ g_assert_nonnull(bs);
24
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
25
+ &error_abort);
26
+ blk_insert_bs(blk, bs, &error_abort);
25
+
27
+
26
snprintf(job_id, sizeof(job_id), "job%u", counter++);
28
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
27
s = block_job_create(job_id, &test_block_job_driver, bs, 0,
29
+ bdrv_set_backing_hd(bs, backing, &error_abort);
28
BLOCK_JOB_DEFAULT, test_block_job_cb,
30
+
29
@@ -XXX,XX +XXX,XX @@ static void test_pair_jobs_fail_cancel_race(void)
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
+
30
int main(int argc, char **argv)
60
int main(int argc, char **argv)
31
{
61
{
32
qemu_init_main_loop(&error_abort);
62
bdrv_init();
33
+ bdrv_init();
63
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
34
64
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
35
g_test_init(&argc, &argv, NULL);
65
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
36
g_test_add_func("/single/success", test_single_job_success);
66
37
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
67
+ g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
38
index XXXXXXX..XXXXXXX 100644
68
+ g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
39
--- a/tests/test-blockjob.c
40
+++ b/tests/test-blockjob.c
41
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
42
static BlockBackend *create_blk(const char *name)
43
{
44
BlockBackend *blk = blk_new();
45
- BlockDriverState *bs = bdrv_new();
46
+ BlockDriverState *bs;
47
+
69
+
48
+ bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
70
return g_test_run();
49
+ g_assert_nonnull(bs);
71
}
50
51
blk_insert_bs(blk, bs);
52
bdrv_unref(bs);
53
@@ -XXX,XX +XXX,XX @@ static void test_job_ids(void)
54
int main(int argc, char **argv)
55
{
56
qemu_init_main_loop(&error_abort);
57
+ bdrv_init();
58
59
g_test_init(&argc, &argv, NULL);
60
g_test_add_func("/blockjob/ids", test_job_ids);
61
--
72
--
62
1.8.3.1
73
2.13.6
63
74
64
75
diff view generated by jsdifflib
New patch
1
Block jobs already paused themselves when their main BlockBackend
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.
1
5
6
This implements .drained_begin/end callbacks in child_job in order to
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.
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
blockjob.c | 22 +++++++++-------------
14
1 file changed, 9 insertions(+), 13 deletions(-)
15
16
diff --git a/blockjob.c b/blockjob.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/blockjob.c
19
+++ b/blockjob.c
20
@@ -XXX,XX +XXX,XX @@ static char *child_job_get_parent_desc(BdrvChild *c)
21
job->id);
22
}
23
24
-static const BdrvChildRole child_job = {
25
- .get_parent_desc = child_job_get_parent_desc,
26
- .stay_at_node = true,
27
-};
28
-
29
-static void block_job_drained_begin(void *opaque)
30
+static void child_job_drained_begin(BdrvChild *c)
31
{
32
- BlockJob *job = opaque;
33
+ BlockJob *job = c->opaque;
34
block_job_pause(job);
35
}
36
37
-static void block_job_drained_end(void *opaque)
38
+static void child_job_drained_end(BdrvChild *c)
39
{
40
- BlockJob *job = opaque;
41
+ BlockJob *job = c->opaque;
42
block_job_resume(job);
43
}
44
45
-static const BlockDevOps block_job_dev_ops = {
46
- .drained_begin = block_job_drained_begin,
47
- .drained_end = block_job_drained_end,
48
+static const BdrvChildRole child_job = {
49
+ .get_parent_desc = child_job_get_parent_desc,
50
+ .drained_begin = child_job_drained_begin,
51
+ .drained_end = child_job_drained_end,
52
+ .stay_at_node = true,
53
};
54
55
void block_job_remove_all_bdrv(BlockJob *job)
56
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
57
block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
58
bs->job = job;
59
60
- blk_set_dev_ops(blk, &block_job_dev_ops, job);
61
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
62
63
QLIST_INSERT_HEAD(&block_jobs, job, job_list);
64
--
65
2.13.6
66
67
diff view generated by jsdifflib
1
This is a function that doesn't do any option parsing, but just does
1
Block jobs must be paused if any of the involved nodes are drained.
2
some basic BlockDriverState setup and calls the .bdrv_open() function of
3
the block driver.
4
2
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
4
---
8
block.c | 112 +++++++++++++++++++++++++++++++++++++---------------------------
5
tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++
9
1 file changed, 65 insertions(+), 47 deletions(-)
6
1 file changed, 121 insertions(+)
10
7
11
diff --git a/block.c b/block.c
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
12
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
10
--- a/tests/test-bdrv-drain.c
14
+++ b/block.c
11
+++ b/tests/test-bdrv-drain.c
15
@@ -XXX,XX +XXX,XX @@ out:
12
@@ -XXX,XX +XXX,XX @@
16
g_free(gen_node_name);
13
14
#include "qemu/osdep.h"
15
#include "block/block.h"
16
+#include "block/blockjob_int.h"
17
#include "sysemu/block-backend.h"
18
#include "qapi/error.h"
19
20
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
21
test_quiesce_common(BDRV_DRAIN, false);
17
}
22
}
18
23
19
+static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
24
+
20
+ const char *node_name, QDict *options,
25
+typedef struct TestBlockJob {
21
+ int open_flags, Error **errp)
26
+ BlockJob common;
27
+ bool should_complete;
28
+} TestBlockJob;
29
+
30
+static void test_job_completed(BlockJob *job, void *opaque)
22
+{
31
+{
23
+ Error *local_err = NULL;
32
+ block_job_completed(job, 0);
33
+}
34
+
35
+static void coroutine_fn test_job_start(void *opaque)
36
+{
37
+ TestBlockJob *s = opaque;
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,
56
+};
57
+
58
+static void test_blockjob_common(enum drain_type drain_type)
59
+{
60
+ BlockBackend *blk_src, *blk_target;
61
+ BlockDriverState *src, *target;
62
+ BlockJob *job;
24
+ int ret;
63
+ int ret;
25
+
64
+
26
+ bdrv_assign_node_name(bs, node_name, &local_err);
65
+ src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR,
27
+ if (local_err) {
66
+ &error_abort);
28
+ error_propagate(errp, local_err);
67
+ blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
29
+ return -EINVAL;
68
+ blk_insert_bs(blk_src, src, &error_abort);
69
+
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);
30
+ }
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 */
31
+
96
+
32
+ bs->drv = drv;
97
+ do_drain_end(drain_type, src);
33
+ bs->opaque = g_malloc0(drv->instance_size);
34
+
98
+
35
+ if (drv->bdrv_file_open) {
99
+ g_assert_cmpint(job->pause_count, ==, 0);
36
+ assert(!drv->bdrv_needs_filename || bs->filename[0]);
100
+ g_assert_false(job->paused);
37
+ ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
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);
38
+ } else {
109
+ } else {
39
+ ret = drv->bdrv_open(bs, options, open_flags, &local_err);
110
+ g_assert_cmpint(job->pause_count, ==, 1);
40
+ }
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 */
41
+
115
+
42
+ if (ret < 0) {
116
+ do_drain_end(drain_type, target);
43
+ if (local_err) {
44
+ error_propagate(errp, local_err);
45
+ } else if (bs->filename[0]) {
46
+ error_setg_errno(errp, -ret, "Could not open '%s'", bs->filename);
47
+ } else {
48
+ error_setg_errno(errp, -ret, "Could not open image");
49
+ }
50
+ goto free_and_fail;
51
+ }
52
+
117
+
53
+ ret = refresh_total_sectors(bs, bs->total_sectors);
118
+ g_assert_cmpint(job->pause_count, ==, 0);
54
+ if (ret < 0) {
119
+ g_assert_false(job->paused);
55
+ error_setg_errno(errp, -ret, "Could not refresh total sector count");
120
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
56
+ goto free_and_fail;
57
+ }
58
+
121
+
59
+ bdrv_refresh_limits(bs, &local_err);
122
+ ret = block_job_complete_sync(job, &error_abort);
60
+ if (local_err) {
123
+ g_assert_cmpint(ret, ==, 0);
61
+ error_propagate(errp, local_err);
62
+ ret = -EINVAL;
63
+ goto free_and_fail;
64
+ }
65
+
124
+
66
+ assert(bdrv_opt_mem_align(bs) != 0);
125
+ blk_unref(blk_src);
67
+ assert(bdrv_min_mem_align(bs) != 0);
126
+ blk_unref(blk_target);
68
+ assert(is_power_of_2(bs->bl.request_alignment));
127
+ bdrv_unref(src);
69
+
128
+ bdrv_unref(target);
70
+ return 0;
71
+
72
+free_and_fail:
73
+ /* FIXME Close bs first if already opened*/
74
+ g_free(bs->opaque);
75
+ bs->opaque = NULL;
76
+ bs->drv = NULL;
77
+ return ret;
78
+}
129
+}
79
+
130
+
80
QemuOptsList bdrv_runtime_opts = {
131
+static void test_blockjob_drain_all(void)
81
.name = "bdrv_common",
132
+{
82
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
133
+ test_blockjob_common(BDRV_DRAIN_ALL);
83
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
134
+}
84
trace_bdrv_open_common(bs, filename ?: "", bs->open_flags,
135
+
85
drv->format_name);
136
+static void test_blockjob_drain(void)
86
137
+{
87
- node_name = qemu_opt_get(opts, "node-name");
138
+ test_blockjob_common(BDRV_DRAIN);
88
- bdrv_assign_node_name(bs, node_name, &local_err);
139
+}
89
- if (local_err) {
140
+
90
- error_propagate(errp, local_err);
141
int main(int argc, char **argv)
91
- ret = -EINVAL;
142
{
92
- goto fail_opts;
143
bdrv_init();
93
- }
144
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
94
-
145
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
95
bs->read_only = !(bs->open_flags & BDRV_O_RDWR);
146
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
96
147
97
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
148
+ g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
98
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
149
+ g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
99
}
150
+
100
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), bs->filename);
151
return g_test_run();
101
152
}
102
- bs->drv = drv;
103
- bs->opaque = g_malloc0(drv->instance_size);
104
-
105
/* Open the image, either directly or using a protocol */
106
open_flags = bdrv_open_flags(bs, bs->open_flags);
107
- if (drv->bdrv_file_open) {
108
- assert(file == NULL);
109
- assert(!drv->bdrv_needs_filename || filename != NULL);
110
- ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
111
- } else {
112
- ret = drv->bdrv_open(bs, options, open_flags, &local_err);
113
- }
114
-
115
- if (ret < 0) {
116
- if (local_err) {
117
- error_propagate(errp, local_err);
118
- } else if (bs->filename[0]) {
119
- error_setg_errno(errp, -ret, "Could not open '%s'", bs->filename);
120
- } else {
121
- error_setg_errno(errp, -ret, "Could not open image");
122
- }
123
- goto free_and_fail;
124
- }
125
+ node_name = qemu_opt_get(opts, "node-name");
126
127
- ret = refresh_total_sectors(bs, bs->total_sectors);
128
+ assert(!drv->bdrv_file_open || file == NULL);
129
+ ret = bdrv_open_driver(bs, drv, node_name, options, open_flags, errp);
130
if (ret < 0) {
131
- error_setg_errno(errp, -ret, "Could not refresh total sector count");
132
- goto free_and_fail;
133
- }
134
-
135
- bdrv_refresh_limits(bs, &local_err);
136
- if (local_err) {
137
- error_propagate(errp, local_err);
138
- ret = -EINVAL;
139
- goto free_and_fail;
140
+ goto fail_opts;
141
}
142
143
- assert(bdrv_opt_mem_align(bs) != 0);
144
- assert(bdrv_min_mem_align(bs) != 0);
145
- assert(is_power_of_2(bs->bl.request_alignment));
146
-
147
qemu_opts_del(opts);
148
return 0;
149
150
-free_and_fail:
151
- g_free(bs->opaque);
152
- bs->opaque = NULL;
153
- bs->drv = NULL;
154
fail_opts:
155
qemu_opts_del(opts);
156
return ret;
157
--
153
--
158
1.8.3.1
154
2.13.6
159
155
160
156
diff view generated by jsdifflib
New patch
1
Block jobs are already paused using the BdrvChildRole drain callbacks,
2
so we don't need an additional block_job_pause_all() call.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
block/io.c | 4 ----
7
tests/test-bdrv-drain.c | 10 ++++------
8
2 files changed, 4 insertions(+), 10 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 @@ void bdrv_drain_all_begin(void)
15
* context. */
16
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
17
18
- block_job_pause_all();
19
-
20
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
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
}
27
-
28
- block_job_resume_all();
29
}
30
31
void bdrv_drain_all(void)
32
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/tests/test-bdrv-drain.c
35
+++ b/tests/test-bdrv-drain.c
36
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
37
do_drain_begin(drain_type, src);
38
39
if (drain_type == BDRV_DRAIN_ALL) {
40
- /* bdrv_drain_all() drains both src and target, and involves an
41
- * additional block_job_pause_all() */
42
- g_assert_cmpint(job->pause_count, ==, 3);
43
+ /* bdrv_drain_all() drains both src and target */
44
+ g_assert_cmpint(job->pause_count, ==, 2);
45
} else {
46
g_assert_cmpint(job->pause_count, ==, 1);
47
}
48
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
49
do_drain_begin(drain_type, target);
50
51
if (drain_type == BDRV_DRAIN_ALL) {
52
- /* bdrv_drain_all() drains both src and target, and involves an
53
- * additional block_job_pause_all() */
54
- g_assert_cmpint(job->pause_count, ==, 3);
55
+ /* bdrv_drain_all() drains both src and target */
56
+ g_assert_cmpint(job->pause_count, ==, 2);
57
} else {
58
g_assert_cmpint(job->pause_count, ==, 1);
59
}
60
--
61
2.13.6
62
63
diff view generated by jsdifflib
New patch
1
bdrv_do_drained_begin() restricts the call of parent callbacks and
2
aio_disable_external() to the outermost drain section, but the block
3
driver callbacks are always called. bdrv_do_drained_end() must match
4
this behaviour, otherwise nodes stay drained even if begin/end calls
5
were balanced.
1
6
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
block/io.c | 12 +++++++-----
10
1 file changed, 7 insertions(+), 5 deletions(-)
11
12
diff --git a/block/io.c b/block/io.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/io.c
15
+++ b/block/io.c
16
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
17
18
void bdrv_drained_end(BlockDriverState *bs)
19
{
20
+ int old_quiesce_counter;
21
+
22
if (qemu_in_coroutine()) {
23
bdrv_co_yield_to_drain(bs, false);
24
return;
25
}
26
assert(bs->quiesce_counter > 0);
27
- if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
28
- return;
29
- }
30
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
31
32
/* Re-enable things in child-to-parent order */
33
bdrv_drain_invoke(bs, false, false);
34
- bdrv_parent_drained_end(bs);
35
- aio_enable_external(bdrv_get_aio_context(bs));
36
+ if (old_quiesce_counter == 1) {
37
+ bdrv_parent_drained_end(bs);
38
+ aio_enable_external(bdrv_get_aio_context(bs));
39
+ }
40
}
41
42
/*
43
--
44
2.13.6
45
46
diff view generated by jsdifflib
1
From: Jeff Cody <jcody@redhat.com>
2
3
Since test 137 make uses of qcow2.py, only local files are supported.
4
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
2
---
8
tests/qemu-iotests/137 | 2 +-
3
tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
9
1 file changed, 1 insertion(+), 1 deletion(-)
4
1 file changed, 57 insertions(+)
10
5
11
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
12
index XXXXXXX..XXXXXXX 100755
7
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/137
8
--- a/tests/test-bdrv-drain.c
14
+++ b/tests/qemu-iotests/137
9
+++ b/tests/test-bdrv-drain.c
15
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
10
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
16
. ./common.qemu
11
enum drain_type {
17
12
BDRV_DRAIN_ALL,
18
_supported_fmt qcow2
13
BDRV_DRAIN,
19
-_supported_proto generic
14
+ DRAIN_TYPE_MAX,
20
+_supported_proto file
15
};
21
_supported_os Linux
16
22
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);
23
87
24
--
88
--
25
1.8.3.1
89
2.13.6
26
90
27
91
diff view generated by jsdifflib
New patch
1
1
This is in preparation for subtree drains, i.e. drained sections that
2
affect not only a single node, but recursively all child nodes, too.
3
4
Calling the parent callbacks for drain is pointless when we just came
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.
16
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
include/block/block.h | 4 ++--
20
block.c | 13 +++++++++----
21
block/io.c | 47 ++++++++++++++++++++++++++++++++++-------------
22
3 files changed, 45 insertions(+), 19 deletions(-)
23
24
diff --git a/include/block/block.h b/include/block/block.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/block/block.h
27
+++ b/include/block/block.h
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
101
@@ -XXX,XX +XXX,XX @@
102
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
103
int64_t offset, int bytes, BdrvRequestFlags flags);
104
105
-void bdrv_parent_drained_begin(BlockDriverState *bs)
106
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
107
{
108
BdrvChild *c, *next;
109
110
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
111
+ if (c == ignore) {
112
+ continue;
113
+ }
114
if (c->role->drained_begin) {
115
c->role->drained_begin(c);
116
}
117
}
118
}
119
120
-void bdrv_parent_drained_end(BlockDriverState *bs)
121
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
122
{
123
BdrvChild *c, *next;
124
125
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
126
+ if (c == ignore) {
127
+ continue;
128
+ }
129
if (c->role->drained_end) {
130
c->role->drained_end(c);
131
}
132
@@ -XXX,XX +XXX,XX @@ typedef struct {
133
BlockDriverState *bs;
134
bool done;
135
bool begin;
136
+ BdrvChild *parent;
137
} BdrvCoDrainData;
138
139
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
140
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
141
return waited;
142
}
143
144
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
145
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
146
+
147
static void bdrv_co_drain_bh_cb(void *opaque)
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
+}
208
+
209
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
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
+}
234
+
235
/*
236
* Wait for pending requests to complete on a single BlockDriverState subtree,
237
* and suspend block driver's internal I/O until next request arrives.
238
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
239
/* Stop things in parent-to-child order */
240
aio_context_acquire(aio_context);
241
aio_disable_external(aio_context);
242
- bdrv_parent_drained_begin(bs);
243
+ bdrv_parent_drained_begin(bs, NULL);
244
bdrv_drain_invoke(bs, true, true);
245
aio_context_release(aio_context);
246
247
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
248
/* Re-enable things in child-to-parent order */
249
aio_context_acquire(aio_context);
250
bdrv_drain_invoke(bs, false, true);
251
- bdrv_parent_drained_end(bs);
252
+ bdrv_parent_drained_end(bs, NULL);
253
aio_enable_external(aio_context);
254
aio_context_release(aio_context);
255
}
256
--
257
2.13.6
258
259
diff view generated by jsdifflib
1
This is the part of bdrv_open_child() that opens a BDS with option
1
bdrv_drained_begin() waits for the completion of requests in the whole
2
inheritance, but doesn't attach it as a child to the parent yet.
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
---
10
---
7
block.c | 61 +++++++++++++++++++++++++++++++++++++------------------------
11
include/block/block.h | 13 +++++++++++++
8
1 file changed, 37 insertions(+), 24 deletions(-)
12
block/io.c | 54 ++++++++++++++++++++++++++++++++++++++++-----------
13
2 files changed, 56 insertions(+), 11 deletions(-)
9
14
10
diff --git a/block.c b/block.c
15
diff --git a/include/block/block.h b/include/block/block.h
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/block.c
17
--- a/include/block/block.h
13
+++ b/block.c
18
+++ b/include/block/block.h
14
@@ -XXX,XX +XXX,XX @@ free_exit:
19
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
15
return ret;
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;
16
}
59
}
17
60
18
-/*
61
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
19
- * Opens a disk image whose options are given as BlockdevRef in another block
62
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
20
- * device's options.
63
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
21
- *
64
+ BdrvChild *parent);
22
- * If allow_none is true, no image will be opened if filename is false and no
65
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
23
- * BlockdevRef is given. NULL will be returned, but errp remains unset.
66
+ BdrvChild *parent);
24
- *
67
25
- * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
68
static void bdrv_co_drain_bh_cb(void *opaque)
26
- * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
27
- * itself, all options starting with "${bdref_key}." are considered part of the
28
- * BlockdevRef.
29
- *
30
- * The BlockdevRef will be removed from the options QDict.
31
- */
32
-BdrvChild *bdrv_open_child(const char *filename,
33
- QDict *options, const char *bdref_key,
34
- BlockDriverState* parent,
35
- const BdrvChildRole *child_role,
36
- bool allow_none, Error **errp)
37
+static BlockDriverState *
38
+bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
39
+ BlockDriverState *parent, const BdrvChildRole *child_role,
40
+ bool allow_none, Error **errp)
41
{
69
{
42
- BdrvChild *c = NULL;
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
43
- BlockDriverState *bs;
71
44
+ BlockDriverState *bs = NULL;
72
bdrv_dec_in_flight(bs);
45
QDict *image_options;
73
if (data->begin) {
46
char *bdref_key_dot;
74
- bdrv_do_drained_begin(bs, data->parent);
47
const char *reference;
75
+ bdrv_do_drained_begin(bs, data->recursive, data->parent);
48
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
76
} else {
49
goto done;
77
- bdrv_do_drained_end(bs, data->parent);
78
+ bdrv_do_drained_end(bs, data->recursive, data->parent);
50
}
79
}
51
80
52
- c = bdrv_attach_child(parent, bs, bdref_key, child_role);
81
data->done = true;
53
-
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
54
done:
83
}
55
qdict_del(options, bdref_key);
84
56
- return c;
85
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
57
+ return 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);
58
+}
132
+}
59
+
133
+
60
+/*
134
+void bdrv_subtree_drained_begin(BlockDriverState *bs)
61
+ * Opens a disk image whose options are given as BlockdevRef in another block
62
+ * device's options.
63
+ *
64
+ * If allow_none is true, no image will be opened if filename is false and no
65
+ * BlockdevRef is given. NULL will be returned, but errp remains unset.
66
+ *
67
+ * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
68
+ * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
69
+ * itself, all options starting with "${bdref_key}." are considered part of the
70
+ * BlockdevRef.
71
+ *
72
+ * The BlockdevRef will be removed from the options QDict.
73
+ */
74
+BdrvChild *bdrv_open_child(const char *filename,
75
+ QDict *options, const char *bdref_key,
76
+ BlockDriverState *parent,
77
+ const BdrvChildRole *child_role,
78
+ bool allow_none, Error **errp)
79
+{
135
+{
80
+ BlockDriverState *bs;
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
}
81
+
156
+
82
+ bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_role,
157
+ if (recursive) {
83
+ allow_none, errp);
158
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
84
+ if (bs == NULL) {
159
+ bdrv_do_drained_end(child->bs, true, child);
85
+ return NULL;
160
+ }
86
+ }
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
+}
87
+
169
+
88
+ return bdrv_attach_child(parent, bs, bdref_key, child_role);
170
+void bdrv_subtree_drained_end(BlockDriverState *bs)
171
+{
172
+ bdrv_do_drained_end(bs, true, NULL);
89
}
173
}
90
174
91
static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
175
/*
92
--
176
--
93
1.8.3.1
177
2.13.6
94
178
95
179
diff view generated by jsdifflib
1
From: Jeff Cody <jcody@redhat.com>
1
Add a subtree drain version to the existing test cases.
2
2
3
Some iotests (e.g. 174) try to filter the output of _make_test_image by
4
piping the stdout. Pipe the server stdout to /dev/null, so that filter
5
pipe does not need to wait until process completion.
6
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
4
---
11
tests/qemu-iotests/common.rc | 2 +-
5
tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++-
12
1 file changed, 1 insertion(+), 1 deletion(-)
6
1 file changed, 26 insertions(+), 1 deletion(-)
13
7
14
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
15
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/common.rc
10
--- a/tests/test-bdrv-drain.c
17
+++ b/tests/qemu-iotests/common.rc
11
+++ b/tests/test-bdrv-drain.c
18
@@ -XXX,XX +XXX,XX @@ _make_test_img()
12
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
19
13
enum drain_type {
20
# Start an NBD server on the image file, which is what we'll be talking to
14
BDRV_DRAIN_ALL,
21
if [ $IMGPROTO = "nbd" ]; then
15
BDRV_DRAIN,
22
- eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE &"
16
+ BDRV_SUBTREE_DRAIN,
23
+ eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE >/dev/null &"
17
DRAIN_TYPE_MAX,
24
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
18
};
25
fi
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)
46
{
47
BlockBackend *blk;
48
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
49
test_quiesce_common(BDRV_DRAIN, false);
50
}
51
52
+static void test_quiesce_drain_subtree(void)
53
+{
54
+ test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
55
+}
56
+
57
static void test_nested(void)
58
{
59
BlockBackend *blk;
60
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
61
/* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
62
int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
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);
72
}
73
74
+static void test_blockjob_drain_subtree(void)
75
+{
76
+ test_blockjob_common(BDRV_SUBTREE_DRAIN);
77
+}
78
+
79
int main(int argc, char **argv)
80
{
81
bdrv_init();
82
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
83
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();
26
}
102
}
27
--
103
--
28
1.8.3.1
104
2.13.6
29
105
30
106
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
If bdrv_do_drained_begin/end() are called in coroutine context, they
2
first use a BH to get out of the coroutine context. Call some existing
3
tests again from a coroutine to cover this code path.
2
4
3
Now that we are truncating the file in both PREALLOC_MODE_FULL and
4
PREALLOC_MODE_OFF, not truncating in PREALLOC_MODE_FALLOC looks odd.
5
Add a comment explaining why we do not truncate in this case.
6
7
Signed-off-by: Nir Soffer <nirsof@gmail.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
6
---
10
block/file-posix.c | 7 ++++++-
7
tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 6 insertions(+), 1 deletion(-)
8
1 file changed, 59 insertions(+)
12
9
13
diff --git a/block/file-posix.c b/block/file-posix.c
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
15
--- a/block/file-posix.c
12
--- a/tests/test-bdrv-drain.c
16
+++ b/block/file-posix.c
13
+++ b/tests/test-bdrv-drain.c
17
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
14
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
18
switch (prealloc) {
15
*aio_ret = ret;
19
#ifdef CONFIG_POSIX_FALLOCATE
16
}
20
case PREALLOC_MODE_FALLOC:
17
21
- /* posix_fallocate() doesn't set errno. */
18
+typedef struct CallInCoroutineData {
22
+ /*
19
+ void (*entry)(void);
23
+ * Truncating before posix_fallocate() makes it about twice slower on
20
+ bool done;
24
+ * file systems that do not support fallocate(), trying to check if a
21
+} CallInCoroutineData;
25
+ * block is allocated before allocating it, so don't do that here.
22
+
26
+ */
23
+static coroutine_fn void call_in_coroutine_entry(void *opaque)
27
result = -posix_fallocate(fd, 0, total_size);
24
+{
28
if (result != 0) {
25
+ CallInCoroutineData *data = opaque;
29
+ /* posix_fallocate() doesn't set errno. */
26
+
30
error_setg_errno(errp, -result,
27
+ data->entry();
31
"Could not preallocate data for the new file");
28
+ data->done = true;
32
}
29
+}
30
+
31
+static void call_in_coroutine(void (*entry)(void))
32
+{
33
+ Coroutine *co;
34
+ CallInCoroutineData data = {
35
+ .entry = entry,
36
+ .done = false,
37
+ };
38
+
39
+ co = qemu_coroutine_create(call_in_coroutine_entry, &data);
40
+ qemu_coroutine_enter(co);
41
+ while (!data.done) {
42
+ aio_poll(qemu_get_aio_context(), true);
43
+ }
44
+}
45
+
46
enum drain_type {
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
+}
57
+
58
+static void test_drv_cb_co_drain_subtree(void)
59
+{
60
+ call_in_coroutine(test_drv_cb_drain_subtree);
61
+}
62
+
63
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
64
{
65
BlockBackend *blk;
66
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain_subtree(void)
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
+}
74
+
75
+static void test_quiesce_co_drain_subtree(void)
76
+{
77
+ call_in_coroutine(test_quiesce_drain_subtree);
78
+}
79
+
80
static void test_nested(void)
81
{
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);
91
+
92
+
93
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
94
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
95
g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
96
test_quiesce_drain_subtree);
97
98
+ // XXX bdrv_drain_all() doesn't work in coroutine context
99
+ g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain);
100
+ g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree",
101
+ test_quiesce_co_drain_subtree);
102
+
103
g_test_add_func("/bdrv-drain/nested", test_nested);
104
105
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
33
--
106
--
34
1.8.3.1
107
2.13.6
35
108
36
109
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
Test that drain sections are correctly propagated through the graph.
2
2
3
In a previous commit (qemu-img: Do not truncate before preallocation) we
4
moved truncate to the PREALLOC_MODE_OFF branch to avoid slowdown in
5
posix_fallocate().
6
7
However this change is not optimal when using PREALLOC_MODE_FULL, since
8
knowing the final size from the beginning could allow the file system
9
driver to do less allocations and possibly avoid fragmentation of the
10
file.
11
12
Now we truncate also before doing full preallocation.
13
14
Signed-off-by: Nir Soffer <nirsof@gmail.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
4
---
17
block/file-posix.c | 12 ++++++++++++
5
tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
18
1 file changed, 12 insertions(+)
6
1 file changed, 74 insertions(+)
19
7
20
diff --git a/block/file-posix.c b/block/file-posix.c
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
21
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
22
--- a/block/file-posix.c
10
--- a/tests/test-bdrv-drain.c
23
+++ b/block/file-posix.c
11
+++ b/tests/test-bdrv-drain.c
24
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
12
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
25
#endif
13
blk_unref(blk);
26
case PREALLOC_MODE_FULL:
14
}
27
{
15
28
+ /*
16
+static void test_multiparent(void)
29
+ * Knowing the final size from the beginning could allow the file
17
+{
30
+ * system driver to do less allocations and possibly avoid
18
+ BlockBackend *blk_a, *blk_b;
31
+ * fragmentation of the file.
19
+ BlockDriverState *bs_a, *bs_b, *backing;
32
+ */
20
+ BDRVTestState *a_s, *b_s, *backing_s;
33
+ if (ftruncate(fd, total_size) != 0) {
34
+ result = -errno;
35
+ error_setg_errno(errp, -result, "Could not resize file");
36
+ goto out_close;
37
+ }
38
+
21
+
39
int64_t num = 0, left = total_size;
22
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
40
buf = g_malloc0(65536);
23
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
41
24
+ &error_abort);
42
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
25
+ a_s = bs_a->opaque;
43
break;
26
+ blk_insert_bs(blk_a, bs_a, &error_abort);
44
}
27
+
45
28
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
46
+out_close:
29
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
47
if (qemu_close(fd) != 0 && result == 0) {
30
+ &error_abort);
48
result = -errno;
31
+ b_s = bs_b->opaque;
49
error_setg_errno(errp, -result, "Could not close the new file");
32
+ blk_insert_bs(blk_b, bs_b, &error_abort);
33
+
34
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
35
+ backing_s = backing->opaque;
36
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
37
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
38
+
39
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
40
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
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);
45
+
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
47
+
48
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
49
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
50
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
51
+ g_assert_cmpint(a_s->drain_count, ==, 1);
52
+ g_assert_cmpint(b_s->drain_count, ==, 1);
53
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
54
+
55
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
56
+
57
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 2);
58
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
59
+ g_assert_cmpint(backing->quiesce_counter, ==, 2);
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);
63
+
64
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
65
+
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
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);
72
+
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
74
+
75
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
76
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
77
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
78
+ g_assert_cmpint(a_s->drain_count, ==, 0);
79
+ g_assert_cmpint(b_s->drain_count, ==, 0);
80
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
81
+
82
+ bdrv_unref(backing);
83
+ bdrv_unref(bs_a);
84
+ bdrv_unref(bs_b);
85
+ blk_unref(blk_a);
86
+ blk_unref(blk_b);
87
+}
88
+
89
90
typedef struct TestBlockJob {
91
BlockJob common;
92
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
93
test_quiesce_co_drain_subtree);
94
95
g_test_add_func("/bdrv-drain/nested", test_nested);
96
+ g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
97
98
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
99
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
50
--
100
--
51
1.8.3.1
101
2.13.6
52
102
53
103
diff view generated by jsdifflib
New patch
1
1
We need to remember how many of the drain sections in which a node is
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.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
include/block/block.h | 2 --
12
include/block/block_int.h | 5 +++++
13
block.c | 32 +++++++++++++++++++++++++++++---
14
block/io.c | 28 ++++++++++++++++++++++++----
15
4 files changed, 58 insertions(+), 9 deletions(-)
16
17
diff --git a/include/block/block.h b/include/block/block.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/block.h
20
+++ b/include/block/block.h
21
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs);
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
diff --git a/include/block/block_int.h b/include/block/block_int.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/block/block_int.h
33
+++ b/include/block/block_int.h
34
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
35
36
/* Accessed with atomic ops. */
37
int quiesce_counter;
38
+ int recursive_quiesce_counter;
39
+
40
unsigned int write_gen; /* Current data generation */
41
42
/* Protected by reqs_lock. */
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
44
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
45
BdrvRequestFlags flags);
46
47
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent);
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.
210
--
211
2.13.6
212
213
diff view generated by jsdifflib
1
From: Jeff Cody <jcody@redhat.com>
2
3
Add the ability for shell script tests to exclude specific
4
protocols. This is useful to allow all protocols except ones known to
5
not support a feature used in the test (e.g. .bdrv_create).
6
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
2
---
10
tests/qemu-iotests/common.rc | 12 ++++++++++++
3
tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 12 insertions(+)
4
1 file changed, 80 insertions(+)
12
5
13
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/common.rc
8
--- a/tests/test-bdrv-drain.c
16
+++ b/tests/qemu-iotests/common.rc
9
+++ b/tests/test-bdrv-drain.c
17
@@ -XXX,XX +XXX,XX @@ _supported_proto()
10
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
18
_notrun "not suitable for this image protocol: $IMGPROTO"
11
blk_unref(blk_b);
19
}
12
}
20
13
21
+# tests whether $IMGPROTO is specified as an unsupported image protocol for a test
14
+static void test_graph_change(void)
22
+#
23
+_unsupported_proto()
24
+{
15
+{
25
+ for f; do
16
+ BlockBackend *blk_a, *blk_b;
26
+ if [ "$f" = "$IMGPROTO" ]; then
17
+ BlockDriverState *bs_a, *bs_b, *backing;
27
+ _notrun "not suitable for this image protocol: $IMGPROTO"
18
+ BDRVTestState *a_s, *b_s, *backing_s;
28
+ return
19
+
29
+ fi
20
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
30
+ done
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);
31
+}
91
+}
32
+
92
+
33
# tests whether the host OS is one of the supported OSes for a test
93
34
#
94
typedef struct TestBlockJob {
35
_supported_os()
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);
36
--
104
--
37
1.8.3.1
105
2.13.6
38
106
39
107
diff view generated by jsdifflib
1
We should not try to assign a not yet opened node as the backing file,
1
Since commit bde70715, base is the only node that is reopened in
2
because as soon as the permission system is added it will fail. The
2
commit_start(). This means that the code, which still involves an
3
just added bdrv_new_open_driver() function is the right tool to open a
3
explicit BlockReopenQueue, can now be simplified by using bdrv_reopen().
4
file with an internal driver, use it.
5
6
In case anyone wonders whether that magic fake backing file to trigger a
7
special action on 'commit' actually works today: No, not for me. One
8
reason is that we've been adding a raw format driver on top for several
9
years now and raw doesn't support commit. Other reasons include that the
10
backing file isn't writable and the driver doesn't support reopen, and
11
it's also size 0 and the driver doesn't support bdrv_truncate. All of
12
these are easily fixable, but then 'commit' ended up in an infinite loop
13
deep in the vvfat code for me, so I thought I'd best leave it alone. I'm
14
not really sure what it was supposed to do anyway.
15
4
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Fam Zheng <famz@redhat.com>
18
---
7
---
19
block/vvfat.c | 10 +++++-----
8
block/commit.c | 8 +-------
20
1 file changed, 5 insertions(+), 5 deletions(-)
9
1 file changed, 1 insertion(+), 7 deletions(-)
21
10
22
diff --git a/block/vvfat.c b/block/vvfat.c
11
diff --git a/block/commit.c b/block/commit.c
23
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
24
--- a/block/vvfat.c
13
--- a/block/commit.c
25
+++ b/block/vvfat.c
14
+++ b/block/commit.c
26
@@ -XXX,XX +XXX,XX @@ static void write_target_close(BlockDriverState *bs) {
15
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
27
16
const char *filter_node_name, Error **errp)
28
static BlockDriver vvfat_write_target = {
17
{
29
.format_name = "vvfat_write_target",
18
CommitBlockJob *s;
30
+ .instance_size = sizeof(void*),
19
- BlockReopenQueue *reopen_queue = NULL;
31
.bdrv_co_pwritev = write_target_commit,
20
int orig_base_flags;
32
.bdrv_close = write_target_close,
21
BlockDriverState *iter;
33
};
22
BlockDriverState *commit_top_bs = NULL;
34
@@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
23
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
35
unlink(s->qcow_filename);
24
/* convert base to r/w, if necessary */
36
#endif
25
orig_base_flags = bdrv_get_flags(base);
37
26
if (!(orig_base_flags & BDRV_O_RDWR)) {
38
- backing = bdrv_new();
27
- reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
39
+ backing = bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALLOW_RDWR,
28
- orig_base_flags | BDRV_O_RDWR);
40
+ &error_abort);
29
- }
41
+ *(void**) backing->opaque = s;
42
+
43
bdrv_set_backing_hd(s->bs, backing);
44
bdrv_unref(backing);
45
46
- s->bs->backing->bs->drv = &vvfat_write_target;
47
- s->bs->backing->bs->opaque = g_new(void *, 1);
48
- *(void**)s->bs->backing->bs->opaque = s;
49
-
30
-
50
return 0;
31
- if (reopen_queue) {
51
32
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
52
err:
33
+ bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
34
if (local_err != NULL) {
35
error_propagate(errp, local_err);
36
goto fail;
53
--
37
--
54
1.8.3.1
38
2.13.6
55
39
56
40
diff view generated by jsdifflib
1
The way that attaching bs->file worked was a bit unusual in that it was
1
The bdrv_reopen*() implementation doesn't like it if the graph is
2
the only child that would be attached to a node which is not opened yet.
2
changed between queuing nodes for reopen and actually reopening them
3
Because of this, the block layer couldn't know yet which permissions the
3
(one of the reasons is that queuing can be recursive).
4
driver would eventually need.
5
4
6
This patch moves the point where bs->file is attached to the beginning
5
So instead of draining the device only in bdrv_reopen_multiple(),
7
of the individual .bdrv_open() implementations, so drivers already know
6
require that callers already drained all affected nodes, and assert this
8
what they are going to do with the child. This is also more consistent
7
in bdrv_reopen_queue().
9
with how driver-specific children work.
10
11
For a moment, bdrv_open() gets its own BdrvChild to perform image
12
probing, but instead of directly assigning this BdrvChild to the BDS, it
13
becomes a temporary one and the node name is passed as an option to the
14
drivers, so that they can simply use bdrv_open_child() to create another
15
reference for their own use.
16
17
This duplicated child for (the not opened yet) bs is not the final
18
state, a follow-up patch will change the image probing code to use a
19
BlockBackend, which is completely independent of bs.
20
8
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
23
---
11
---
24
block.c | 35 ++++++++++++++++++++++++-----------
12
block.c | 23 ++++++++++++++++-------
25
block/bochs.c | 6 ++++++
13
block/replication.c | 6 ++++++
26
block/cloop.c | 6 ++++++
14
qemu-io-cmds.c | 3 +++
27
block/crypto.c | 6 ++++++
15
3 files changed, 25 insertions(+), 7 deletions(-)
28
block/dmg.c | 6 ++++++
29
block/parallels.c | 6 ++++++
30
block/qcow.c | 6 ++++++
31
block/qcow2.c | 18 +++++++++++++++---
32
block/qed.c | 18 +++++++++++++++---
33
block/raw-format.c | 6 ++++++
34
block/replication.c | 6 ++++++
35
block/vdi.c | 6 ++++++
36
block/vhdx.c | 6 ++++++
37
block/vmdk.c | 6 ++++++
38
block/vpc.c | 6 ++++++
39
tests/qemu-iotests/051.out | 4 ++--
40
tests/qemu-iotests/051.pc.out | 4 ++--
41
17 files changed, 130 insertions(+), 21 deletions(-)
42
16
43
diff --git a/block.c b/block.c
17
diff --git a/block.c b/block.c
44
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
45
--- a/block.c
19
--- a/block.c
46
+++ b/block.c
20
+++ b/block.c
47
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
21
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
48
assert(!drv->bdrv_needs_filename || filename != NULL);
22
* returns a pointer to bs_queue, which is either the newly allocated
49
ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
23
* bs_queue, or the existing bs_queue being used.
50
} else {
24
*
51
- if (file == NULL) {
25
+ * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple().
52
- error_setg(errp, "Can't use '%s' as a block driver for the "
26
*/
53
- "protocol level", drv->format_name);
27
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
54
- ret = -EINVAL;
28
BlockDriverState *bs,
55
- goto free_and_fail;
29
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
56
- }
30
BdrvChild *child;
57
- bs->file = file;
31
QDict *old_options, *explicit_options;
58
ret = drv->bdrv_open(bs, options, open_flags, &local_err);
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:
59
}
64
}
60
65
g_free(bs_queue);
61
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
66
62
return 0;
67
- bdrv_drain_all_end();
63
68
-
64
free_and_fail:
65
- bs->file = NULL;
66
g_free(bs->opaque);
67
bs->opaque = NULL;
68
bs->drv = NULL;
69
@@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
70
}
71
72
if (child->bs->inherits_from == parent) {
73
- child->bs->inherits_from = NULL;
74
+ BdrvChild *c;
75
+
76
+ /* Remove inherits_from only when the last reference between parent and
77
+ * child->bs goes away. */
78
+ QLIST_FOREACH(c, &parent->children, next) {
79
+ if (c != child && c->bs == child->bs) {
80
+ break;
81
+ }
82
+ }
83
+ if (c == NULL) {
84
+ child->bs->inherits_from = NULL;
85
+ }
86
}
87
88
bdrv_root_unref_child(child);
89
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
90
qdict_del(options, "backing");
91
}
92
93
- /* Open image file without format layer */
94
+ /* Open image file without format layer. This BdrvChild is only used for
95
+ * probing, the block drivers will do their own bdrv_open_child() for the
96
+ * same BDS, which is why we put the node name back into options. */
97
if ((flags & BDRV_O_PROTOCOL) == 0) {
98
+ /* FIXME Shouldn't attach a child to a node that isn't opened yet. */
99
file = bdrv_open_child(filename, options, "file", bs,
100
&child_file, true, &local_err);
101
if (local_err) {
102
goto fail;
103
}
104
+ if (file != NULL) {
105
+ qdict_put(options, "file",
106
+ qstring_from_str(bdrv_get_node_name(file->bs)));
107
+ }
108
}
109
110
/* Image format probing */
111
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
112
goto fail;
113
}
114
115
- if (file && (bs->file != file)) {
116
+ if (file) {
117
bdrv_unref_child(bs, file);
118
file = NULL;
119
}
120
@@ -XXX,XX +XXX,XX @@ fail:
121
if (file != NULL) {
122
bdrv_unref_child(bs, file);
123
}
124
+ if (bs->file != NULL) {
125
+ bdrv_unref_child(bs, bs->file);
126
+ }
127
QDECREF(snapshot_options);
128
QDECREF(bs->explicit_options);
129
QDECREF(bs->options);
130
diff --git a/block/bochs.c b/block/bochs.c
131
index XXXXXXX..XXXXXXX 100644
132
--- a/block/bochs.c
133
+++ b/block/bochs.c
134
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
135
struct bochs_header bochs;
136
int ret;
137
138
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
139
+ false, errp);
140
+ if (!bs->file) {
141
+ return -EINVAL;
142
+ }
143
+
144
bs->read_only = true; /* no write support yet */
145
146
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
147
diff --git a/block/cloop.c b/block/cloop.c
148
index XXXXXXX..XXXXXXX 100644
149
--- a/block/cloop.c
150
+++ b/block/cloop.c
151
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
152
uint32_t offsets_size, max_compressed_block_size = 1, i;
153
int ret;
154
155
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
156
+ false, errp);
157
+ if (!bs->file) {
158
+ return -EINVAL;
159
+ }
160
+
161
bs->read_only = true;
162
163
/* read header */
164
diff --git a/block/crypto.c b/block/crypto.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/block/crypto.c
167
+++ b/block/crypto.c
168
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
169
QCryptoBlockOpenOptions *open_opts = NULL;
170
unsigned int cflags = 0;
171
172
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
173
+ false, errp);
174
+ if (!bs->file) {
175
+ return -EINVAL;
176
+ }
177
+
178
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
179
qemu_opts_absorb_qdict(opts, options, &local_err);
180
if (local_err) {
181
diff --git a/block/dmg.c b/block/dmg.c
182
index XXXXXXX..XXXXXXX 100644
183
--- a/block/dmg.c
184
+++ b/block/dmg.c
185
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
186
int64_t offset;
187
int ret;
188
189
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
190
+ false, errp);
191
+ if (!bs->file) {
192
+ return -EINVAL;
193
+ }
194
+
195
block_module_load_one("dmg-bz2");
196
bs->read_only = true;
197
198
diff --git a/block/parallels.c b/block/parallels.c
199
index XXXXXXX..XXXXXXX 100644
200
--- a/block/parallels.c
201
+++ b/block/parallels.c
202
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
203
Error *local_err = NULL;
204
char *buf;
205
206
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
207
+ false, errp);
208
+ if (!bs->file) {
209
+ return -EINVAL;
210
+ }
211
+
212
ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
213
if (ret < 0) {
214
goto fail;
215
diff --git a/block/qcow.c b/block/qcow.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/block/qcow.c
218
+++ b/block/qcow.c
219
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
220
QCowHeader header;
221
Error *local_err = NULL;
222
223
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
224
+ false, errp);
225
+ if (!bs->file) {
226
+ return -EINVAL;
227
+ }
228
+
229
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
230
if (ret < 0) {
231
goto fail;
232
diff --git a/block/qcow2.c b/block/qcow2.c
233
index XXXXXXX..XXXXXXX 100644
234
--- a/block/qcow2.c
235
+++ b/block/qcow2.c
236
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
237
return ret;
69
return ret;
238
}
70
}
239
71
240
-static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
72
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
241
- Error **errp)
242
+static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
243
+ Error **errp)
244
{
73
{
245
BDRVQcow2State *s = bs->opaque;
74
int ret = -1;
246
unsigned int len, i;
75
Error *local_err = NULL;
247
@@ -XXX,XX +XXX,XX @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
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
+
248
return ret;
89
return ret;
249
}
90
}
250
91
251
+static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
252
+ Error **errp)
253
+{
254
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
255
+ false, errp);
256
+ if (!bs->file) {
257
+ return -EINVAL;
258
+ }
259
+
260
+ return qcow2_do_open(bs, options, flags, errp);
261
+}
262
+
263
static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
264
{
265
BDRVQcow2State *s = bs->opaque;
266
@@ -XXX,XX +XXX,XX @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
267
options = qdict_clone_shallow(bs->options);
268
269
flags &= ~BDRV_O_INACTIVE;
270
- ret = qcow2_open(bs, options, flags, &local_err);
271
+ ret = qcow2_do_open(bs, options, flags, &local_err);
272
QDECREF(options);
273
if (local_err) {
274
error_propagate(errp, local_err);
275
diff --git a/block/qed.c b/block/qed.c
276
index XXXXXXX..XXXXXXX 100644
277
--- a/block/qed.c
278
+++ b/block/qed.c
279
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_drain(BlockDriverState *bs)
280
}
281
}
282
283
-static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
284
- Error **errp)
285
+static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
286
+ Error **errp)
287
{
288
BDRVQEDState *s = bs->opaque;
289
QEDHeader le_header;
290
@@ -XXX,XX +XXX,XX @@ out:
291
return ret;
292
}
293
294
+static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
295
+ Error **errp)
296
+{
297
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
298
+ false, errp);
299
+ if (!bs->file) {
300
+ return -EINVAL;
301
+ }
302
+
303
+ return bdrv_qed_do_open(bs, options, flags, errp);
304
+}
305
+
306
static void bdrv_qed_refresh_limits(BlockDriverState *bs, Error **errp)
307
{
308
BDRVQEDState *s = bs->opaque;
309
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
310
bdrv_qed_close(bs);
311
312
memset(s, 0, sizeof(BDRVQEDState));
313
- ret = bdrv_qed_open(bs, NULL, bs->open_flags, &local_err);
314
+ ret = bdrv_qed_do_open(bs, NULL, bs->open_flags, &local_err);
315
if (local_err) {
316
error_propagate(errp, local_err);
317
error_prepend(errp, "Could not reopen qed layer: ");
318
diff --git a/block/raw-format.c b/block/raw-format.c
319
index XXXXXXX..XXXXXXX 100644
320
--- a/block/raw-format.c
321
+++ b/block/raw-format.c
322
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
323
BDRVRawState *s = bs->opaque;
324
int ret;
325
326
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
327
+ false, errp);
328
+ if (!bs->file) {
329
+ return -EINVAL;
330
+ }
331
+
332
bs->sg = bs->file->bs->sg;
333
bs->supported_write_flags = BDRV_REQ_FUA &
334
bs->file->bs->supported_write_flags;
335
diff --git a/block/replication.c b/block/replication.c
92
diff --git a/block/replication.c b/block/replication.c
336
index XXXXXXX..XXXXXXX 100644
93
index XXXXXXX..XXXXXXX 100644
337
--- a/block/replication.c
94
--- a/block/replication.c
338
+++ b/block/replication.c
95
+++ b/block/replication.c
339
@@ -XXX,XX +XXX,XX @@ static int replication_open(BlockDriverState *bs, QDict *options,
96
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
340
const char *mode;
97
new_secondary_flags = s->orig_secondary_flags;
341
const char *top_id;
98
}
342
99
343
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
100
+ bdrv_subtree_drained_begin(s->hidden_disk->bs);
344
+ false, errp);
101
+ bdrv_subtree_drained_begin(s->secondary_disk->bs);
345
+ if (!bs->file) {
346
+ return -EINVAL;
347
+ }
348
+
102
+
349
ret = -EINVAL;
103
if (orig_hidden_flags != new_hidden_flags) {
350
opts = qemu_opts_create(&replication_runtime_opts, NULL, 0, &error_abort);
104
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
351
qemu_opts_absorb_qdict(opts, options, &local_err);
105
new_hidden_flags);
352
diff --git a/block/vdi.c b/block/vdi.c
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
353
index XXXXXXX..XXXXXXX 100644
117
index XXXXXXX..XXXXXXX 100644
354
--- a/block/vdi.c
118
--- a/qemu-io-cmds.c
355
+++ b/block/vdi.c
119
+++ b/qemu-io-cmds.c
356
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
120
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
357
int ret;
121
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
358
Error *local_err = NULL;
122
qemu_opts_reset(&reopen_opts);
359
123
360
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
124
+ bdrv_subtree_drained_begin(bs);
361
+ false, errp);
125
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
362
+ if (!bs->file) {
126
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
363
+ return -EINVAL;
127
+ bdrv_subtree_drained_end(bs);
364
+ }
365
+
128
+
366
logout("\n");
367
368
ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
369
diff --git a/block/vhdx.c b/block/vhdx.c
370
index XXXXXXX..XXXXXXX 100644
371
--- a/block/vhdx.c
372
+++ b/block/vhdx.c
373
@@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
374
uint64_t signature;
375
Error *local_err = NULL;
376
377
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
378
+ false, errp);
379
+ if (!bs->file) {
380
+ return -EINVAL;
381
+ }
382
+
383
s->bat = NULL;
384
s->first_visible_write = true;
385
386
diff --git a/block/vmdk.c b/block/vmdk.c
387
index XXXXXXX..XXXXXXX 100644
388
--- a/block/vmdk.c
389
+++ b/block/vmdk.c
390
@@ -XXX,XX +XXX,XX @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
391
uint32_t magic;
392
Error *local_err = NULL;
393
394
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
395
+ false, errp);
396
+ if (!bs->file) {
397
+ return -EINVAL;
398
+ }
399
+
400
buf = vmdk_read_desc(bs->file, 0, errp);
401
if (!buf) {
402
return -EINVAL;
403
diff --git a/block/vpc.c b/block/vpc.c
404
index XXXXXXX..XXXXXXX 100644
405
--- a/block/vpc.c
406
+++ b/block/vpc.c
407
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
408
int disk_type = VHD_DYNAMIC;
409
int ret;
410
411
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
412
+ false, errp);
413
+ if (!bs->file) {
414
+ return -EINVAL;
415
+ }
416
+
417
opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
418
qemu_opts_absorb_qdict(opts, options, &local_err);
419
if (local_err) {
129
if (local_err) {
420
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
130
error_report_err(local_err);
421
index XXXXXXX..XXXXXXX 100644
131
} else {
422
--- a/tests/qemu-iotests/051.out
423
+++ b/tests/qemu-iotests/051.out
424
@@ -XXX,XX +XXX,XX @@ Testing: -drive driver=nbd
425
QEMU_PROG: -drive driver=nbd: NBD server address missing
426
427
Testing: -drive driver=raw
428
-QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level
429
+QEMU_PROG: -drive driver=raw: A block device must be specified for "file"
430
431
Testing: -drive file.driver=file
432
QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name
433
@@ -XXX,XX +XXX,XX @@ Testing: -drive file.driver=nbd
434
QEMU_PROG: -drive file.driver=nbd: NBD server address missing
435
436
Testing: -drive file.driver=raw
437
-QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level
438
+QEMU_PROG: -drive file.driver=raw: A block device must be specified for "file"
439
440
Testing: -drive foo=bar
441
QEMU_PROG: -drive foo=bar: Must specify either driver or file
442
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
443
index XXXXXXX..XXXXXXX 100644
444
--- a/tests/qemu-iotests/051.pc.out
445
+++ b/tests/qemu-iotests/051.pc.out
446
@@ -XXX,XX +XXX,XX @@ Testing: -drive driver=nbd
447
QEMU_PROG: -drive driver=nbd: NBD server address missing
448
449
Testing: -drive driver=raw
450
-QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level
451
+QEMU_PROG: -drive driver=raw: A block device must be specified for "file"
452
453
Testing: -drive file.driver=file
454
QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name
455
@@ -XXX,XX +XXX,XX @@ Testing: -drive file.driver=nbd
456
QEMU_PROG: -drive file.driver=nbd: NBD server address missing
457
458
Testing: -drive file.driver=raw
459
-QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level
460
+QEMU_PROG: -drive file.driver=raw: A block device must be specified for "file"
461
462
Testing: -drive foo=bar
463
QEMU_PROG: -drive foo=bar: Must specify either driver or file
464
--
132
--
465
1.8.3.1
133
2.13.6
466
134
467
135
diff view generated by jsdifflib