1
The following changes since commit 38441756b70eec5807b5f60dad11a93a91199866:
1
The following changes since commit 281f327487c9c9b1599f93c589a408bbf4a651b8:
2
2
3
Update version for v3.0.0 release (2018-08-14 16:38:43 +0100)
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
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to b5fc2d306664c0c1c6c5cf8e164ffa7b8892283e:
9
for you to fetch changes up to 1a63a907507fbbcfaee3f622907ec244b7eabda8:
10
10
11
qapi: block: Remove mentions of error types which were removed (2018-08-15 12:50:39 +0200)
11
block: Keep nodes drained between reopen_queue/multiple (2017-12-22 15:05:32 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
16
- Remove deprecated -drive options for geometry/serial/addr
17
- luks: Allow shared writers if the parents allow them (share-rw=on)
18
- qemu-img: Fix error when trying to convert to encrypted target image
19
- mirror: Fail gracefully for source == target
20
- I/O throttling: Fix behaviour during drain (always ignore the limits)
21
- bdrv_reopen() related fixes for bs->options/explicit_options content
22
- Documentation improvements
23
15
24
----------------------------------------------------------------
16
----------------------------------------------------------------
25
Alberto Garcia (9):
17
Doug Gale (1):
26
qemu-iotests: Test removing a throttle group member with a pending timer
18
nvme: Add tracing
27
throttle-groups: Skip the round-robin if a member is being drained
28
qemu-iotests: Update 093 to improve the draining test
29
throttle-groups: Don't allow timers without throttled requests
30
qdict: Make qdict_extract_subqdict() accept dst = NULL
31
block: Remove children options from bs->{options,explicit_options}
32
block: Simplify bdrv_reopen_abort()
33
block: Update bs->options if bdrv_reopen() succeeds
34
block: Simplify append_open_options()
35
19
36
Daniel P. Berrangé (1):
20
Edgar Kaziakhmedov (1):
37
qemu-img: fix regression copying secrets during convert
21
qcow2: get rid of qcow2_backing_read1 routine
38
22
39
Fam Zheng (1):
23
Fam Zheng (2):
40
luks: Allow share-rw=on
24
block: Open backing image in force share mode for size probe
25
block: Remove unused bdrv_requests_pending
41
26
42
Kevin Wolf (7):
27
John Snow (1):
43
block/qapi: Fix memory leak in qmp_query_blockstats()
28
iotests: fix 197 for vpc
44
block: Remove deprecated -drive geometry options
45
block: Remove deprecated -drive option addr
46
block: Remove deprecated -drive option serial
47
block: Remove dead deprecation warning code
48
qapi/block: Document restrictions for node names
49
mirror: Fail gracefully for source == target
50
29
51
Peter Krempa (1):
30
Kevin Wolf (27):
52
qapi: block: Remove mentions of error types which were removed
31
block: Formats don't need CONSISTENT_READ with NO_IO
32
block: Make bdrv_drain_invoke() recursive
33
block: Call .drain_begin only once in bdrv_drain_all_begin()
34
test-bdrv-drain: Test BlockDriver callbacks for drain
35
block: bdrv_drain_recurse(): Remove unused begin parameter
36
block: Don't wait for requests in bdrv_drain*_end()
37
block: Unify order in drain functions
38
block: Don't acquire AioContext in hmp_qemu_io()
39
block: Document that x-blockdev-change breaks quorum children list
40
block: Assert drain_all is only called from main AioContext
41
block: Make bdrv_drain() driver callbacks non-recursive
42
test-bdrv-drain: Test callback for bdrv_drain
43
test-bdrv-drain: Test bs->quiesce_counter
44
blockjob: Pause job on draining any job BDS
45
test-bdrv-drain: Test drain vs. block jobs
46
block: Don't block_job_pause_all() in bdrv_drain_all()
47
block: Nested drain_end must still call callbacks
48
test-bdrv-drain: Test nested drain sections
49
block: Don't notify parents in drain call chain
50
block: Add bdrv_subtree_drained_begin/end()
51
test-bdrv-drain: Tests for bdrv_subtree_drain
52
test-bdrv-drain: Test behaviour in coroutine context
53
test-bdrv-drain: Recursive draining with multiple parents
54
block: Allow graph changes in subtree drained section
55
test-bdrv-drain: Test graph changes in drained section
56
commit: Simplify reopen of base
57
block: Keep nodes drained between reopen_queue/multiple
53
58
54
Vladimir Sementsov-Ogievskiy (2):
59
Thomas Huth (3):
55
block: make .bdrv_close optional
60
block: Remove the obsolete -drive boot=on|off parameter
56
block: drop empty .bdrv_close handlers
61
block: Remove the deprecated -hdachs option
62
block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter
57
63
58
qapi/block-core.json | 8 ++--
64
qapi/block-core.json | 4 +
59
include/hw/block/block.h | 1 -
65
block/qcow2.h | 3 -
60
include/sysemu/blockdev.h | 3 --
66
include/block/block.h | 15 +-
61
block.c | 46 ++++++++++++++-----
67
include/block/block_int.h | 6 +-
62
block/blkreplay.c | 5 ---
68
block.c | 75 ++++-
63
block/block-backend.c | 1 -
69
block/commit.c | 8 +-
64
block/commit.c | 5 ---
70
block/io.c | 164 +++++++---
65
block/copy-on-read.c | 6 ---
71
block/qcow2.c | 51 +--
66
block/crypto.c | 4 +-
72
block/replication.c | 6 +
67
block/mirror.c | 10 ++---
73
blockdev.c | 11 -
68
block/null.c | 6 ---
74
blockjob.c | 22 +-
69
block/qapi.c | 3 +-
75
hmp.c | 6 -
70
block/raw-format.c | 5 ---
76
hw/block/nvme.c | 349 +++++++++++++++++----
71
block/snapshot.c | 4 +-
77
qemu-io-cmds.c | 3 +
72
block/throttle-groups.c | 41 ++++++++++++-----
78
tests/test-bdrv-drain.c | 651 +++++++++++++++++++++++++++++++++++++++
73
blockdev.c | 110 ---------------------------------------------
79
vl.c | 86 +-----
74
device-hotplug.c | 4 --
80
hw/block/trace-events | 93 ++++++
75
hw/block/block.c | 27 -----------
81
qemu-doc.texi | 29 +-
76
hw/block/nvme.c | 1 -
82
qemu-options.hx | 19 +-
77
hw/block/virtio-blk.c | 1 -
83
tests/Makefile.include | 2 +
78
hw/ide/qdev.c | 1 -
84
tests/qemu-iotests/197 | 4 +
79
hw/scsi/scsi-disk.c | 1 -
85
tests/qemu-iotests/common.filter | 3 +-
80
hw/usb/dev-storage.c | 1 -
86
22 files changed, 1294 insertions(+), 316 deletions(-)
81
qemu-img.c | 32 +++++++------
87
create mode 100644 tests/test-bdrv-drain.c
82
qobject/block-qdict.c | 11 +++--
83
tests/ahci-test.c | 6 +--
84
tests/hd-geo-test.c | 37 +++------------
85
tests/ide-test.c | 8 ++--
86
hmp-commands.hx | 1 -
87
qemu-deprecated.texi | 15 -------
88
qemu-options.hx | 14 +-----
89
tests/qemu-iotests/041 | 6 +++
90
tests/qemu-iotests/041.out | 4 +-
91
tests/qemu-iotests/093 | 55 +++++++++++++++++++++++
92
tests/qemu-iotests/093.out | 4 +-
93
35 files changed, 185 insertions(+), 302 deletions(-)
94
88
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently
2
in use as a mirror target. It is not enough for image formats, though,
3
as these still unconditionally request BLK_PERM_CONSISTENT_READ.
2
4
3
If a bdrv_reopen_multiple() call fails, then the explicit_options
5
As this permission is geared towards whether the guest-visible data is
4
QDict has to be deleted for every entry in the reopen queue. This must
6
consistent, and has no impact on whether the metadata is sane, and
5
happen regardless of whether that entry's bdrv_reopen_prepare() call
7
'qemu-img info' does not read guest-visible data (except for the raw
6
succeeded or not.
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.
7
10
8
This patch simplifies the cleanup code a bit.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
12
---
13
block.c | 9 ++++-----
13
block.c | 6 +++++-
14
1 file changed, 4 insertions(+), 5 deletions(-)
14
1 file changed, 5 insertions(+), 1 deletion(-)
15
15
16
diff --git a/block.c b/block.c
16
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
18
--- a/block.c
19
+++ b/block.c
19
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
20
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
21
21
assert(role == &child_backing || role == &child_file);
22
cleanup:
22
23
QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
23
if (!backing) {
24
- if (ret && bs_entry->prepared) {
24
+ int flags = bdrv_reopen_get_flags(reopen_queue, bs);
25
- bdrv_reopen_abort(&bs_entry->state);
25
+
26
- } else if (ret) {
26
/* Apart from the modifications below, the same permissions are
27
+ if (ret) {
27
* forwarded and left alone as for filters */
28
+ if (bs_entry->prepared) {
28
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
29
+ bdrv_reopen_abort(&bs_entry->state);
29
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
30
+ }
30
31
qobject_unref(bs_entry->state.explicit_options);
31
/* bs->file always needs to be consistent because of the metadata. We
32
}
32
* can never allow other users to resize or write to it. */
33
qobject_unref(bs_entry->state.options);
33
- perm |= BLK_PERM_CONSISTENT_READ;
34
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
34
+ if (!(flags & BDRV_O_NO_IO)) {
35
drv->bdrv_reopen_abort(reopen_state);
35
+ perm |= BLK_PERM_CONSISTENT_READ;
36
}
36
+ }
37
37
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
38
- qobject_unref(reopen_state->explicit_options);
38
} else {
39
-
39
/* We want consistent read from backing files if the parent needs it.
40
bdrv_abort_perm_update(reopen_state->bs);
41
}
42
43
--
40
--
44
2.13.6
41
2.13.6
45
42
46
43
diff view generated by jsdifflib
New patch
1
From: John Snow <jsnow@redhat.com>
1
2
3
VPC has some difficulty creating geometries of particular size.
4
However, we can indeed force it to use a literal one, so let's
5
do that for the sake of test 197, which is testing some specific
6
offsets.
7
8
Signed-off-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Lukáš Doktor <ldoktor@redhat.com>
13
---
14
tests/qemu-iotests/197 | 4 ++++
15
tests/qemu-iotests/common.filter | 3 ++-
16
2 files changed, 6 insertions(+), 1 deletion(-)
17
18
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/197
21
+++ b/tests/qemu-iotests/197
22
@@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ==='
23
echo
24
25
# Prep the images
26
+# VPC rounds image sizes to a specific geometry, force a specific size.
27
+if [ "$IMGFMT" = "vpc" ]; then
28
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
29
+fi
30
_make_test_img 4G
31
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
32
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
33
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
34
index XXXXXXX..XXXXXXX 100644
35
--- a/tests/qemu-iotests/common.filter
36
+++ b/tests/qemu-iotests/common.filter
37
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
38
-e "s# log_size=[0-9]\\+##g" \
39
-e "s# refcount_bits=[0-9]\\+##g" \
40
-e "s# key-secret=[a-zA-Z0-9]\\+##g" \
41
- -e "s# iter-time=[0-9]\\+##g"
42
+ -e "s# iter-time=[0-9]\\+##g" \
43
+ -e "s# force_size=\\(on\\|off\\)##g"
44
}
45
46
_filter_img_info()
47
--
48
2.13.6
49
50
diff view generated by jsdifflib
1
blockdev-mirror with the same node for source and target segfaults
1
This change separates bdrv_drain_invoke(), which calls the BlockDriver
2
today: A node is in its own backing chain, so mirror_start_job() decides
2
drain callbacks, from bdrv_drain_recurse(). Instead, the function
3
that this is an active commit. When adding the intermediate nodes with
3
performs its own recursion now.
4
block_job_add_bdrv(), it starts the iteration through the subchain with
5
the backing file of source, though, so it never reaches target and
6
instead runs into NULL at the base.
7
4
8
While we could fix that by starting with source itself, there is no
5
One reason for this is that bdrv_drain_recurse() can be called multiple
9
point in allowing mirroring a node into itself and I wouldn't be
6
times by bdrv_drain_all_begin(), but the callbacks may only be called
10
surprised if this caused more problems later.
7
once. The separation is necessary to fix this bug.
11
8
12
So just check for this scenario and error out.
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.
13
15
14
Cc: qemu-stable@nongnu.org
16
Cc: qemu-stable@nongnu.org
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
19
---
18
block/mirror.c | 5 +++++
20
block/io.c | 14 +++++++++++---
19
tests/qemu-iotests/041 | 6 ++++++
21
1 file changed, 11 insertions(+), 3 deletions(-)
20
tests/qemu-iotests/041.out | 4 ++--
21
3 files changed, 13 insertions(+), 2 deletions(-)
22
22
23
diff --git a/block/mirror.c b/block/mirror.c
23
diff --git a/block/io.c b/block/io.c
24
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/mirror.c
25
--- a/block/io.c
26
+++ b/block/mirror.c
26
+++ b/block/io.c
27
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
28
buf_size = DEFAULT_MIRROR_BUF_SIZE;
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);
29
}
61
}
30
62
31
+ if (bs == target) {
63
+ bdrv_drain_invoke(bs, true);
32
+ error_setg(errp, "Can't mirror node into itself");
64
bdrv_drain_recurse(bs, true);
33
+ return;
65
}
34
+ }
66
35
+
67
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
36
/* In the case of active commit, add dummy driver to provide consistent
68
}
37
* reads on the top, while disabling it in the intermediate nodes, and make
69
38
* the backing chain writable. */
70
bdrv_parent_drained_end(bs);
39
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
71
+ bdrv_drain_invoke(bs, false);
40
index XXXXXXX..XXXXXXX 100755
72
bdrv_drain_recurse(bs, false);
41
--- a/tests/qemu-iotests/041
73
aio_enable_external(bdrv_get_aio_context(bs));
42
+++ b/tests/qemu-iotests/041
74
}
43
@@ -XXX,XX +XXX,XX @@ class TestSingleBlockdev(TestSingleDrive):
75
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
44
result = self.vm.qmp("blockdev-add", **args)
76
aio_context_acquire(aio_context);
45
self.assert_qmp(result, 'return', {})
77
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
46
78
if (aio_context == bdrv_get_aio_context(bs)) {
47
+ def test_mirror_to_self(self):
79
+ /* FIXME Calling this multiple times is wrong */
48
+ result = self.vm.qmp(self.qmp_cmd, job_id='job0',
80
+ bdrv_drain_invoke(bs, true);
49
+ device=self.qmp_target, sync='full',
81
waited |= bdrv_drain_recurse(bs, true);
50
+ target=self.qmp_target)
82
}
51
+ self.assert_qmp(result, 'error/class', 'GenericError')
83
}
52
+
84
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
53
test_large_cluster = None
85
aio_context_acquire(aio_context);
54
test_image_not_found = None
86
aio_enable_external(aio_context);
55
test_small_buffer2 = None
87
bdrv_parent_drained_end(bs);
56
diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
88
+ bdrv_drain_invoke(bs, false);
57
index XXXXXXX..XXXXXXX 100644
89
bdrv_drain_recurse(bs, false);
58
--- a/tests/qemu-iotests/041.out
90
aio_context_release(aio_context);
59
+++ b/tests/qemu-iotests/041.out
91
}
60
@@ -XXX,XX +XXX,XX @@
61
-.....................................................................................
62
+........................................................................................
63
----------------------------------------------------------------------
64
-Ran 85 tests
65
+Ran 88 tests
66
67
OK
68
--
92
--
69
2.13.6
93
2.13.6
70
94
71
95
diff view generated by jsdifflib
1
For BlockBackends that are skipped in query-blockstats, we would leak
1
bdrv_drain_all_begin() used to call the .bdrv_co_drain_begin() driver
2
info since commit 567dcb31. Allocate info only later to avoid the memory
2
callback inside its polling loop. This means that how many times it got
3
leak.
3
called for each node depended on long it had to poll the event loop.
4
4
5
Fixes: CID 1394727
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
6
Cc: qemu-stable@nongnu.org
11
Cc: qemu-stable@nongnu.org
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
14
---
10
block/qapi.c | 3 ++-
15
block/io.c | 3 +--
11
1 file changed, 2 insertions(+), 1 deletion(-)
16
1 file changed, 1 insertion(+), 2 deletions(-)
12
17
13
diff --git a/block/qapi.c b/block/qapi.c
18
diff --git a/block/io.c b/block/io.c
14
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qapi.c
20
--- a/block/io.c
16
+++ b/block/qapi.c
21
+++ b/block/io.c
17
@@ -XXX,XX +XXX,XX @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
22
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
18
}
23
aio_context_acquire(aio_context);
19
} else {
24
bdrv_parent_drained_begin(bs);
20
for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) {
25
aio_disable_external(aio_context);
21
- BlockStatsList *info = g_malloc0(sizeof(*info));
26
+ bdrv_drain_invoke(bs, true);
22
+ BlockStatsList *info;
27
aio_context_release(aio_context);
23
AioContext *ctx = blk_get_aio_context(blk);
28
24
BlockStats *s;
29
if (!g_slist_find(aio_ctxs, aio_context)) {
25
char *qdev;
30
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
26
@@ -XXX,XX +XXX,XX @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
31
aio_context_acquire(aio_context);
27
bdrv_query_blk_stats(s->stats, blk);
32
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
28
aio_context_release(ctx);
33
if (aio_context == bdrv_get_aio_context(bs)) {
29
34
- /* FIXME Calling this multiple times is wrong */
30
+ info = g_malloc0(sizeof(*info));
35
- bdrv_drain_invoke(bs, true);
31
info->value = s;
36
waited |= bdrv_drain_recurse(bs, true);
32
*p_next = info;
37
}
33
p_next = &info->next;
38
}
34
--
39
--
35
2.13.6
40
2.13.6
36
41
37
42
diff view generated by jsdifflib
New patch
1
This adds a test case that the BlockDriver callbacks for drain are
2
called in bdrv_drained_all_begin/end(), and that both of them are called
3
exactly once.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
9
tests/test-bdrv-drain.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++
10
tests/Makefile.include | 2 +
11
2 files changed, 139 insertions(+)
12
create mode 100644 tests/test-bdrv-drain.c
13
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
15
new file mode 100644
16
index XXXXXXX..XXXXXXX
17
--- /dev/null
18
+++ b/tests/test-bdrv-drain.c
19
@@ -XXX,XX +XXX,XX @@
20
+/*
21
+ * Block node draining tests
22
+ *
23
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
24
+ *
25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
26
+ * of this software and associated documentation files (the "Software"), to deal
27
+ * in the Software without restriction, including without limitation the rights
28
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29
+ * copies of the Software, and to permit persons to whom the Software is
30
+ * furnished to do so, subject to the following conditions:
31
+ *
32
+ * The above copyright notice and this permission notice shall be included in
33
+ * all copies or substantial portions of the Software.
34
+ *
35
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41
+ * THE SOFTWARE.
42
+ */
43
+
44
+#include "qemu/osdep.h"
45
+#include "block/block.h"
46
+#include "sysemu/block-backend.h"
47
+#include "qapi/error.h"
48
+
49
+typedef struct BDRVTestState {
50
+ int drain_count;
51
+} BDRVTestState;
52
+
53
+static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
54
+{
55
+ BDRVTestState *s = bs->opaque;
56
+ s->drain_count++;
57
+}
58
+
59
+static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
60
+{
61
+ BDRVTestState *s = bs->opaque;
62
+ s->drain_count--;
63
+}
64
+
65
+static void bdrv_test_close(BlockDriverState *bs)
66
+{
67
+ BDRVTestState *s = bs->opaque;
68
+ g_assert_cmpint(s->drain_count, >, 0);
69
+}
70
+
71
+static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
72
+ uint64_t offset, uint64_t bytes,
73
+ QEMUIOVector *qiov, int flags)
74
+{
75
+ /* We want this request to stay until the polling loop in drain waits for
76
+ * it to complete. We need to sleep a while as bdrv_drain_invoke() comes
77
+ * first and polls its result, too, but it shouldn't accidentally complete
78
+ * this request yet. */
79
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
80
+
81
+ return 0;
82
+}
83
+
84
+static BlockDriver bdrv_test = {
85
+ .format_name = "test",
86
+ .instance_size = sizeof(BDRVTestState),
87
+
88
+ .bdrv_close = bdrv_test_close,
89
+ .bdrv_co_preadv = bdrv_test_co_preadv,
90
+
91
+ .bdrv_co_drain_begin = bdrv_test_co_drain_begin,
92
+ .bdrv_co_drain_end = bdrv_test_co_drain_end,
93
+};
94
+
95
+static void aio_ret_cb(void *opaque, int ret)
96
+{
97
+ int *aio_ret = opaque;
98
+ *aio_ret = ret;
99
+}
100
+
101
+static void test_drv_cb_drain_all(void)
102
+{
103
+ BlockBackend *blk;
104
+ BlockDriverState *bs;
105
+ BDRVTestState *s;
106
+ BlockAIOCB *acb;
107
+ int aio_ret;
108
+
109
+ QEMUIOVector qiov;
110
+ struct iovec iov = {
111
+ .iov_base = NULL,
112
+ .iov_len = 0,
113
+ };
114
+ qemu_iovec_init_external(&qiov, &iov, 1);
115
+
116
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
117
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
118
+ &error_abort);
119
+ s = bs->opaque;
120
+ blk_insert_bs(blk, bs, &error_abort);
121
+
122
+ /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */
123
+ g_assert_cmpint(s->drain_count, ==, 0);
124
+ bdrv_drain_all_begin();
125
+ g_assert_cmpint(s->drain_count, ==, 1);
126
+ bdrv_drain_all_end();
127
+ g_assert_cmpint(s->drain_count, ==, 0);
128
+
129
+ /* Now do the same while a request is pending */
130
+ aio_ret = -EINPROGRESS;
131
+ acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret);
132
+ g_assert(acb != NULL);
133
+ g_assert_cmpint(aio_ret, ==, -EINPROGRESS);
134
+
135
+ g_assert_cmpint(s->drain_count, ==, 0);
136
+ bdrv_drain_all_begin();
137
+ g_assert_cmpint(aio_ret, ==, 0);
138
+ g_assert_cmpint(s->drain_count, ==, 1);
139
+ bdrv_drain_all_end();
140
+ g_assert_cmpint(s->drain_count, ==, 0);
141
+
142
+ bdrv_unref(bs);
143
+ blk_unref(blk);
144
+}
145
+
146
+int main(int argc, char **argv)
147
+{
148
+ bdrv_init();
149
+ qemu_init_main_loop(&error_abort);
150
+
151
+ g_test_init(&argc, &argv, NULL);
152
+
153
+ g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
154
+
155
+ return g_test_run();
156
+}
157
diff --git a/tests/Makefile.include b/tests/Makefile.include
158
index XXXXXXX..XXXXXXX 100644
159
--- a/tests/Makefile.include
160
+++ b/tests/Makefile.include
161
@@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c
162
gcov-files-test-hbitmap-y = util/hbitmap.c
163
check-unit-y += tests/test-hbitmap$(EXESUF)
164
gcov-files-test-hbitmap-y = blockjob.c
165
+check-unit-y += tests/test-bdrv-drain$(EXESUF)
166
check-unit-y += tests/test-blockjob$(EXESUF)
167
check-unit-y += tests/test-blockjob-txn$(EXESUF)
168
check-unit-y += tests/test-x86-cpuid$(EXESUF)
169
@@ -XXX,XX +XXX,XX @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
170
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
171
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
172
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
173
+tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
174
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
175
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
176
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
177
--
178
2.13.6
179
180
diff view generated by jsdifflib
New patch
1
Now that the bdrv_drain_invoke() calls are pulled up to the callers of
2
bdrv_drain_recurse(), the 'begin' parameter isn't needed any more.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/io.c | 12 ++++++------
8
1 file changed, 6 insertions(+), 6 deletions(-)
9
10
diff --git a/block/io.c b/block/io.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/io.c
13
+++ b/block/io.c
14
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
15
}
16
}
17
18
-static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
19
+static bool bdrv_drain_recurse(BlockDriverState *bs)
20
{
21
BdrvChild *child, *tmp;
22
bool waited;
23
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
24
*/
25
bdrv_ref(bs);
26
}
27
- waited |= bdrv_drain_recurse(bs, begin);
28
+ waited |= bdrv_drain_recurse(bs);
29
if (in_main_loop) {
30
bdrv_unref(bs);
31
}
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
33
}
34
35
bdrv_drain_invoke(bs, true);
36
- bdrv_drain_recurse(bs, true);
37
+ bdrv_drain_recurse(bs);
38
}
39
40
void bdrv_drained_end(BlockDriverState *bs)
41
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
42
43
bdrv_parent_drained_end(bs);
44
bdrv_drain_invoke(bs, false);
45
- bdrv_drain_recurse(bs, false);
46
+ bdrv_drain_recurse(bs);
47
aio_enable_external(bdrv_get_aio_context(bs));
48
}
49
50
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
51
aio_context_acquire(aio_context);
52
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
53
if (aio_context == bdrv_get_aio_context(bs)) {
54
- waited |= bdrv_drain_recurse(bs, true);
55
+ waited |= bdrv_drain_recurse(bs);
56
}
57
}
58
aio_context_release(aio_context);
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
60
aio_enable_external(aio_context);
61
bdrv_parent_drained_end(bs);
62
bdrv_drain_invoke(bs, false);
63
- bdrv_drain_recurse(bs, false);
64
+ bdrv_drain_recurse(bs);
65
aio_context_release(aio_context);
66
}
67
68
--
69
2.13.6
70
71
diff view generated by jsdifflib
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
New patch
1
Drain requests are propagated to child nodes, parent nodes and directly
2
to the AioContext. The order in which this happened was different
3
between all combinations of drain/drain_all and begin/end.
1
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.
13
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
---
17
block/io.c | 12 ++++++++----
18
1 file changed, 8 insertions(+), 4 deletions(-)
19
20
diff --git a/block/io.c b/block/io.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/io.c
23
+++ b/block/io.c
24
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
25
return;
26
}
27
28
+ /* Stop things in parent-to-child order */
29
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
30
aio_disable_external(bdrv_get_aio_context(bs));
31
bdrv_parent_drained_begin(bs);
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
33
return;
34
}
35
36
- bdrv_parent_drained_end(bs);
37
+ /* Re-enable things in child-to-parent order */
38
bdrv_drain_invoke(bs, false);
39
+ bdrv_parent_drained_end(bs);
40
aio_enable_external(bdrv_get_aio_context(bs));
41
}
42
43
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
44
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
45
AioContext *aio_context = bdrv_get_aio_context(bs);
46
47
+ /* Stop things in parent-to-child order */
48
aio_context_acquire(aio_context);
49
- bdrv_parent_drained_begin(bs);
50
aio_disable_external(aio_context);
51
+ bdrv_parent_drained_begin(bs);
52
bdrv_drain_invoke(bs, true);
53
aio_context_release(aio_context);
54
55
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
56
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
57
AioContext *aio_context = bdrv_get_aio_context(bs);
58
59
+ /* Re-enable things in child-to-parent order */
60
aio_context_acquire(aio_context);
61
- aio_enable_external(aio_context);
62
- bdrv_parent_drained_end(bs);
63
bdrv_drain_invoke(bs, false);
64
+ bdrv_parent_drained_end(bs);
65
+ aio_enable_external(aio_context);
66
aio_context_release(aio_context);
67
}
68
69
--
70
2.13.6
71
72
diff view generated by jsdifflib
New patch
1
Commit 15afd94a047 added code to acquire and release the AioContext in
2
qemuio_command(). This means that the lock is taken twice now in the
3
call path from hmp_qemu_io(). This causes BDRV_POLL_WHILE() to hang for
4
any requests issued to nodes in a non-mainloop AioContext.
1
5
6
Dropping the first locking from hmp_qemu_io() fixes the problem.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
hmp.c | 6 ------
12
1 file changed, 6 deletions(-)
13
14
diff --git a/hmp.c b/hmp.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hmp.c
17
+++ b/hmp.c
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
}
28
}
29
30
- aio_context = blk_get_aio_context(blk);
31
- aio_context_acquire(aio_context);
32
-
33
/*
34
* Notably absent: Proper permission management. This is sad, but it seems
35
* almost impossible to achieve without changing the semantics and thereby
36
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
37
*/
38
qemuio_command(blk, command);
39
40
- aio_context_release(aio_context);
41
-
42
fail:
43
blk_unref(local_blk);
44
hmp_handle_error(mon, &err);
45
--
46
2.13.6
47
48
diff view generated by jsdifflib
1
From: Peter Krempa <pkrempa@redhat.com>
1
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
2
2
3
Most of the various error classes were removed prior to the 1.2 release.
3
Since bdrv_co_preadv does all neccessary checks including
4
Remove mentions of the error classes which did not make it.
4
reading after the end of the backing file, avoid duplication
5
of verification before bdrv_co_preadv call.
5
6
6
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
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>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
11
---
9
qapi/block-core.json | 5 +----
12
block/qcow2.h | 3 ---
10
1 file changed, 1 insertion(+), 4 deletions(-)
13
block/qcow2.c | 51 ++++++++-------------------------------------------
14
2 files changed, 8 insertions(+), 46 deletions(-)
11
15
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
diff --git a/block/qcow2.h b/block/qcow2.h
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/block-core.json
18
--- a/block/qcow2.h
15
+++ b/qapi/block-core.json
19
+++ b/block/qcow2.h
16
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
17
# autogenerated. (Since: 2.9)
21
}
18
#
22
19
# Returns: Nothing on success
23
/* qcow2.c functions */
20
-# If commit or stream is already active on this device, DeviceInUse
24
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
21
# If @device does not exist, DeviceNotFound
25
- int64_t sector_num, int nb_sectors);
22
-# If image commit is not supported by this device, NotSupported
26
-
23
-# If @base or @top is invalid, a generic error is returned
27
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
24
-# If @speed is invalid, InvalidParameter
28
int refcount_order, bool generous_increase,
25
+# Any other error returns a GenericError.
29
uint64_t *refblock_count);
26
#
30
diff --git a/block/qcow2.c b/block/qcow2.c
27
# Since: 1.3
31
index XXXXXXX..XXXXXXX 100644
28
#
32
--- a/block/qcow2.c
33
+++ b/block/qcow2.c
34
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
35
return status;
36
}
37
38
-/* handle reading after the end of the backing file */
39
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
40
- int64_t offset, int bytes)
41
-{
42
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
43
- int n1;
44
-
45
- if ((offset + bytes) <= bs_size) {
46
- return bytes;
47
- }
48
-
49
- if (offset >= bs_size) {
50
- n1 = 0;
51
- } else {
52
- n1 = bs_size - offset;
53
- }
54
-
55
- qemu_iovec_memset(qiov, n1, 0, bytes - n1);
56
-
57
- return n1;
58
-}
59
-
60
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
61
uint64_t bytes, QEMUIOVector *qiov,
62
int flags)
63
{
64
BDRVQcow2State *s = bs->opaque;
65
- int offset_in_cluster, n1;
66
+ int offset_in_cluster;
67
int ret;
68
unsigned int cur_bytes; /* number of bytes in current iteration */
69
uint64_t cluster_offset = 0;
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
71
case QCOW2_CLUSTER_UNALLOCATED:
72
73
if (bs->backing) {
74
- /* read from the base image */
75
- n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
76
- offset, cur_bytes);
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 */
29
--
104
--
30
2.13.6
105
2.13.6
31
106
32
107
diff view generated by jsdifflib
1
blockdev-add fails if an invalid node name is given, so we should
1
Removing a quorum child node with x-blockdev-change results in a quorum
2
document what a valid node name even is.
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().
3
5
4
Reported-by: Cong Li <coli@redhat.com>
6
Document this problem so that we won't accidentally mark the command
7
stable without having addressed it.
8
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Cong Li <coli@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
---
11
---
10
qapi/block-core.json | 3 +++
12
qapi/block-core.json | 4 ++++
11
1 file changed, 3 insertions(+)
13
1 file changed, 4 insertions(+)
12
14
13
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/qapi/block-core.json
17
--- a/qapi/block-core.json
16
+++ b/qapi/block-core.json
18
+++ b/qapi/block-core.json
17
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
18
# @driver: block driver name
20
# does not support all kinds of operations, all kinds of children, nor
19
# @node-name: the node name of the new node (Since 2.0).
21
# all block drivers.
20
# This option is required on the top level of blockdev-add.
22
#
21
+# Valid node names start with an alphabetic character and may
23
+# FIXME Removing children from a quorum node means introducing gaps in the
22
+# contain only alphanumeric characters, '-', '.' and '_'. Their
24
+# child indices. This cannot be represented in the 'children' list of
23
+# maximum length is 31 characters.
25
+# BlockdevOptionsQuorum, as returned by .bdrv_refresh_filename().
24
# @discard: discard-related options (default: ignore)
26
+#
25
# @cache: cache-related options
27
# Warning: The data in a new quorum child MUST be consistent with that of
26
# @read-only: whether the block device should be read-only (default: false).
28
# the rest of the array.
29
#
27
--
30
--
28
2.13.6
31
2.13.6
29
32
30
33
diff view generated by jsdifflib
1
This reinstates commit b0083267444a5e0f28391f6c2831a539f878d424,
1
From: Doug Gale <doug16k@gmail.com>
2
which was temporarily reverted for the 3.0 release so that libvirt gets
3
some extra time to update their command lines.
4
2
5
The -drive option serial was deprecated in QEMU 2.10. It's time to
3
Add trace output for commands, errors, and undefined behavior.
6
remove it.
4
Add guest error log output for undefined behavior.
5
Report invalid undefined accesses to MMIO.
6
Annotate unlikely error checks with unlikely.
7
7
8
Tests need to be updated to set the serial number with -global instead
8
Signed-off-by: Doug Gale <doug16k@gmail.com>
9
of using the -drive option.
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(-)
10
16
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Markus Armbruster <armbru@redhat.com>
13
Reviewed-by: Jeff Cody <jcody@redhat.com>
14
---
15
include/hw/block/block.h | 1 -
16
include/sysemu/blockdev.h | 1 -
17
block/block-backend.c | 1 -
18
blockdev.c | 10 ----------
19
hw/block/block.c | 13 -------------
20
hw/block/nvme.c | 1 -
21
hw/block/virtio-blk.c | 1 -
22
hw/ide/qdev.c | 1 -
23
hw/scsi/scsi-disk.c | 1 -
24
hw/usb/dev-storage.c | 1 -
25
tests/ahci-test.c | 6 +++---
26
tests/ide-test.c | 8 ++++----
27
qemu-deprecated.texi | 5 -----
28
qemu-options.hx | 6 +-----
29
14 files changed, 8 insertions(+), 48 deletions(-)
30
31
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/block/block.h
34
+++ b/include/hw/block/block.h
35
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
36
37
/* Configuration helpers */
38
39
-void blkconf_serial(BlockConf *conf, char **serial);
40
bool blkconf_geometry(BlockConf *conf, int *trans,
41
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
42
Error **errp);
43
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
44
index XXXXXXX..XXXXXXX 100644
45
--- a/include/sysemu/blockdev.h
46
+++ b/include/sysemu/blockdev.h
47
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
48
bool is_default; /* Added by default_drive() ? */
49
int media_cd;
50
QemuOpts *opts;
51
- char *serial;
52
QTAILQ_ENTRY(DriveInfo) next;
53
};
54
55
diff --git a/block/block-backend.c b/block/block-backend.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/block-backend.c
58
+++ b/block/block-backend.c
59
@@ -XXX,XX +XXX,XX @@ static void drive_info_del(DriveInfo *dinfo)
60
return;
61
}
62
qemu_opts_del(dinfo->opts);
63
- g_free(dinfo->serial);
64
g_free(dinfo);
65
}
66
67
diff --git a/blockdev.c b/blockdev.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/blockdev.c
70
+++ b/blockdev.c
71
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
72
.type = QEMU_OPT_STRING,
73
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
74
},{
75
- .name = "serial",
76
- .type = QEMU_OPT_STRING,
77
- .help = "disk serial number",
78
- },{
79
.name = "file",
80
.type = QEMU_OPT_STRING,
81
.help = "file name",
82
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
83
const char *werror, *rerror;
84
bool read_only = false;
85
bool copy_on_read;
86
- const char *serial;
87
const char *filename;
88
Error *local_err = NULL;
89
int i;
90
const char *deprecated[] = {
91
- "serial"
92
};
93
94
/* Change legacy command line options into QMP ones */
95
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
96
goto fail;
97
}
98
99
- /* Serial number */
100
- serial = qemu_opt_get(legacy_opts, "serial");
101
-
102
/* no id supplied -> create one */
103
if (qemu_opts_id(all_opts) == NULL) {
104
char *new_id;
105
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
106
dinfo->type = type;
107
dinfo->bus = bus_id;
108
dinfo->unit = unit_id;
109
- dinfo->serial = g_strdup(serial);
110
111
blk_set_legacy_dinfo(blk, dinfo);
112
113
diff --git a/hw/block/block.c b/hw/block/block.c
114
index XXXXXXX..XXXXXXX 100644
115
--- a/hw/block/block.c
116
+++ b/hw/block/block.c
117
@@ -XXX,XX +XXX,XX @@
118
#include "qapi/qapi-types-block.h"
119
#include "qemu/error-report.h"
120
121
-void blkconf_serial(BlockConf *conf, char **serial)
122
-{
123
- DriveInfo *dinfo;
124
-
125
- if (!*serial) {
126
- /* try to fall back to value set with legacy -drive serial=... */
127
- dinfo = blk_legacy_dinfo(conf->blk);
128
- if (dinfo) {
129
- *serial = g_strdup(dinfo->serial);
130
- }
131
- }
132
-}
133
-
134
void blkconf_blocksizes(BlockConf *conf)
135
{
136
BlockBackend *blk = conf->blk;
137
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
138
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
139
--- a/hw/block/nvme.c
19
--- a/hw/block/nvme.c
140
+++ b/hw/block/nvme.c
20
+++ b/hw/block/nvme.c
141
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
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);
142
return;
619
return;
143
}
620
}
144
621
145
- blkconf_serial(&n->conf, &n->serial);
622
if (((addr - 0x1000) >> 2) & 1) {
146
if (!n->serial) {
623
+ /* Completion queue doorbell write */
147
error_setg(errp, "serial property not set");
624
+
148
return;
625
uint16_t new_head = val & 0xffff;
149
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
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
150
index XXXXXXX..XXXXXXX 100644
681
index XXXXXXX..XXXXXXX 100644
151
--- a/hw/block/virtio-blk.c
682
--- a/hw/block/trace-events
152
+++ b/hw/block/virtio-blk.c
683
+++ b/hw/block/trace-events
153
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
684
@@ -XXX,XX +XXX,XX @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6
154
return;
685
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
155
}
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"
156
687
157
- blkconf_serial(&conf->conf, &conf->serial);
688
+# hw/block/nvme.c
158
if (!blkconf_apply_backend_options(&conf->conf,
689
+# nvme traces for successful events
159
blk_is_read_only(conf->conf.blk), true,
690
+nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
160
errp)) {
691
+nvme_irq_pin(void) "pulsing IRQ pin"
161
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
692
+nvme_irq_masked(void) "IRQ is masked"
162
index XXXXXXX..XXXXXXX 100644
693
+nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
163
--- a/hw/ide/qdev.c
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""
164
+++ b/hw/ide/qdev.c
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""
165
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
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"
166
return;
697
+nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
167
}
698
+nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16""
168
699
+nvme_identify_ctrl(void) "identify controller"
169
- blkconf_serial(&dev->conf, &dev->serial);
700
+nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
170
if (kind != IDE_CD) {
701
+nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
171
if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
702
+nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s"
172
errp)) {
703
+nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
173
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
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"
174
index XXXXXXX..XXXXXXX 100644
705
+nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
175
--- a/hw/scsi/scsi-disk.c
706
+nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
176
+++ b/hw/scsi/scsi-disk.c
707
+nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
177
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
708
+nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
178
return;
709
+nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
179
}
710
+nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
180
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""
181
- blkconf_serial(&s->qdev.conf, &s->serial);
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""
182
blkconf_blocksizes(&s->qdev.conf);
713
+nvme_mmio_start_success(void) "setting controller enable bit succeeded"
183
714
+nvme_mmio_stopped(void) "cleared controller enable bit"
184
if (s->qdev.conf.logical_block_size >
715
+nvme_mmio_shutdown_set(void) "shutdown bit set"
185
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
716
+nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
186
index XXXXXXX..XXXXXXX 100644
717
+
187
--- a/hw/usb/dev-storage.c
718
+# nvme traces for error conditions
188
+++ b/hw/usb/dev-storage.c
719
+nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
189
@@ -XXX,XX +XXX,XX @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
720
+nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
190
return;
721
+nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
191
}
722
+nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
192
723
+nvme_err_invalid_field(void) "invalid field"
193
- blkconf_serial(&s->conf, &dev->serial);
724
+nvme_err_invalid_prp(void) "invalid PRP"
194
blkconf_blocksizes(&s->conf);
725
+nvme_err_invalid_sgl(void) "invalid SGL"
195
if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
726
+nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u"
196
errp)) {
727
+nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
197
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
728
+nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
198
index XXXXXXX..XXXXXXX 100644
729
+nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
199
--- a/tests/ahci-test.c
730
+nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
200
+++ b/tests/ahci-test.c
731
+nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
201
@@ -XXX,XX +XXX,XX @@ static AHCIQState *ahci_boot(const char *cli, ...)
732
+nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
202
s = ahci_vboot(cli, ap);
733
+nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
203
va_end(ap);
734
+nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
204
} else {
735
+nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
205
- cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s"
736
+nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
206
- ",format=%s"
737
+nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
207
+ cli = "-drive if=none,id=drive0,file=%s,cache=writeback,format=%s"
738
+nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
208
" -M q35 "
739
+nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
209
"-device ide-hd,drive=drive0 "
740
+nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
210
+ "-global ide-hd.serial=%s "
741
+nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
211
"-global ide-hd.ver=%s";
742
+nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
212
- s = ahci_boot(cli, tmp_path, "testdisk", imgfmt, "version");
743
+nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
213
+ s = ahci_boot(cli, tmp_path, imgfmt, "testdisk", "version");
744
+nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
214
}
745
+nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
215
746
+nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
216
return s;
747
+nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
217
diff --git a/tests/ide-test.c b/tests/ide-test.c
748
+nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
218
index XXXXXXX..XXXXXXX 100644
749
+nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null"
219
--- a/tests/ide-test.c
750
+nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64""
220
+++ b/tests/ide-test.c
751
+nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64""
221
@@ -XXX,XX +XXX,XX @@ static void test_bmdma_no_busmaster(void)
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"
222
static void test_bmdma_setup(void)
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"
223
{
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"
224
ide_test_start(
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"
225
- "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
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"
226
- "-global ide-hd.ver=%s",
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"
227
+ "-drive file=%s,if=ide,cache=writeback,format=raw "
758
+nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
228
+ "-global ide-hd.serial=%s -global ide-hd.ver=%s",
759
+nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
229
tmp_path, "testdisk", "version");
760
+nvme_err_startfail(void) "setting controller enable bit failed"
230
qtest_irq_intercept_in(global_qtest, "ioapic");
761
+
231
}
762
+# Traces for undefined behavior
232
@@ -XXX,XX +XXX,XX @@ static void test_identify(void)
763
+nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64""
233
int ret;
764
+nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u"
234
765
+nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled"
235
ide_test_start(
766
+nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status"
236
- "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
767
+nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)"
237
- "-global ide-hd.ver=%s",
768
+nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
238
+ "-drive file=%s,if=ide,cache=writeback,format=raw "
769
+nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
239
+ "-global ide-hd.serial=%s -global ide-hd.ver=%s",
770
+nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
240
tmp_path, "testdisk", "version");
771
+nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
241
772
+nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
242
dev = get_pci_device(&bmdma_bar, &ide_bar);
773
+nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
243
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
774
+nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0"
244
index XXXXXXX..XXXXXXX 100644
775
+nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring"
245
--- a/qemu-deprecated.texi
776
+nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring"
246
+++ b/qemu-deprecated.texi
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"
247
@@ -XXX,XX +XXX,XX @@ with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
778
+nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring"
248
(for embedded NICs). The new syntax allows different settings to be
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"
249
provided per NIC.
780
+
250
781
# hw/block/xen_disk.c
251
-@subsection -drive serial=... (since 2.10.0)
782
xen_disk_alloc(char *name) "%s"
252
-
783
xen_disk_init(char *name) "%s"
253
-The drive serial argument is replaced by the the serial argument
254
-that can be specified with the ``-device'' parameter.
255
-
256
@subsection -usbdevice (since 2.10.0)
257
258
The ``-usbdevice DEV'' argument is now a synonym for setting
259
diff --git a/qemu-options.hx b/qemu-options.hx
260
index XXXXXXX..XXXXXXX 100644
261
--- a/qemu-options.hx
262
+++ b/qemu-options.hx
263
@@ -XXX,XX +XXX,XX @@ ETEXI
264
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
265
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
266
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
267
- " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
268
+ " [,snapshot=on|off][,rerror=ignore|stop|report]\n"
269
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
270
" [,readonly=on|off][,copy-on-read=on|off]\n"
271
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
272
@@ -XXX,XX +XXX,XX @@ The default mode is @option{cache=writeback}.
273
Specify which disk @var{format} will be used rather than detecting
274
the format. Can be used to specify format=raw to avoid interpreting
275
an untrusted format header.
276
-@item serial=@var{serial}
277
-This option specifies the serial number to assign to the device. This
278
-parameter is deprecated, use the corresponding parameter of @code{-device}
279
-instead.
280
@item werror=@var{action},rerror=@var{action}
281
Specify which @var{action} to take on write and read errors. Valid actions are:
282
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
283
--
784
--
284
2.13.6
785
2.13.6
285
786
286
787
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
This function returns a BDS's driver-specific options, excluding also
3
Management tools create overlays of running guests with qemu-img:
4
those from its children. Since we have just removed all children
5
options from bs->options there's no need to do this last step.
6
4
7
We allow references to children, though ("backing": "node0"), so those
5
$ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2
8
we still have to remove.
9
6
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
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>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
18
---
13
block.c | 7 ++-----
19
block.c | 3 ++-
14
1 file changed, 2 insertions(+), 5 deletions(-)
20
1 file changed, 2 insertions(+), 1 deletion(-)
15
21
16
diff --git a/block.c b/block.c
22
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
24
--- a/block.c
19
+++ b/block.c
25
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ static bool append_open_options(QDict *d, BlockDriverState *bs)
26
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
21
QemuOptDesc *desc;
27
back_flags = flags;
22
BdrvChild *child;
28
back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
23
bool found_any = false;
29
24
- const char *p;
30
+ backing_options = qdict_new();
25
31
if (backing_fmt) {
26
for (entry = qdict_first(bs->options); entry;
32
- backing_options = qdict_new();
27
entry = qdict_next(bs->options, entry))
33
qdict_put_str(backing_options, "driver", backing_fmt);
28
{
29
- /* Exclude options for children */
30
+ /* Exclude node-name references to children */
31
QLIST_FOREACH(child, &bs->children, next) {
32
- if (strstart(qdict_entry_key(entry), child->name, &p)
33
- && (!*p || *p == '.'))
34
- {
35
+ if (!strcmp(entry->key, child->name)) {
36
break;
37
}
38
}
34
}
35
+ qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true);
36
37
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
38
&local_err);
39
--
39
--
40
2.13.6
40
2.13.6
41
41
42
42
diff view generated by jsdifflib
1
This reinstates commit a7aff6dd10b16b67e8b142d0c94c5d92c3fe88f6,
1
From: Thomas Huth <thuth@redhat.com>
2
which was temporarily reverted for the 3.0 release so that libvirt gets
3
some extra time to update their command lines.
4
2
5
The -drive options cyls, heads, secs and trans were deprecated in
3
It's not working anymore since QEMU v1.3.0 - time to remove it now.
6
QEMU 2.10. It's time to remove them.
7
4
8
hd-geo-test tested both the old version with geometry options in -drive
5
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
and the new one with -device. Therefore the code using -drive doesn't
6
Reviewed-by: John Snow <jsnow@redhat.com>
10
have to be replaced there, we just need to remove the -drive test cases.
7
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
This in turn allows some simplification of the code.
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
blockdev.c | 11 -----------
11
qemu-doc.texi | 6 ------
12
2 files changed, 17 deletions(-)
12
13
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Markus Armbruster <armbru@redhat.com>
15
---
16
include/sysemu/blockdev.h | 1 -
17
blockdev.c | 75 +----------------------------------------------
18
hw/block/block.c | 14 ---------
19
tests/hd-geo-test.c | 37 +++++------------------
20
hmp-commands.hx | 1 -
21
qemu-deprecated.texi | 5 ----
22
qemu-options.hx | 7 +----
23
7 files changed, 9 insertions(+), 131 deletions(-)
24
25
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
26
index XXXXXXX..XXXXXXX 100644
27
--- a/include/sysemu/blockdev.h
28
+++ b/include/sysemu/blockdev.h
29
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
30
int auto_del; /* see blockdev_mark_auto_del() */
31
bool is_default; /* Added by default_drive() ? */
32
int media_cd;
33
- int cyls, heads, secs, trans;
34
QemuOpts *opts;
35
char *serial;
36
QTAILQ_ENTRY(DriveInfo) next;
37
diff --git a/blockdev.c b/blockdev.c
14
diff --git a/blockdev.c b/blockdev.c
38
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
39
--- a/blockdev.c
16
--- a/blockdev.c
40
+++ b/blockdev.c
17
+++ b/blockdev.c
41
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
18
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
42
.type = QEMU_OPT_STRING,
19
.type = QEMU_OPT_STRING,
43
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
20
.help = "chs translation (auto, lba, none)",
44
},{
21
},{
45
- .name = "cyls",
22
- .name = "boot",
46
- .type = QEMU_OPT_NUMBER,
23
- .type = QEMU_OPT_BOOL,
47
- .help = "number of cylinders (ide disk geometry)",
24
- .help = "(deprecated, ignored)",
48
- },{
49
- .name = "heads",
50
- .type = QEMU_OPT_NUMBER,
51
- .help = "number of heads (ide disk geometry)",
52
- },{
53
- .name = "secs",
54
- .type = QEMU_OPT_NUMBER,
55
- .help = "number of sectors (ide disk geometry)",
56
- },{
57
- .name = "trans",
58
- .type = QEMU_OPT_STRING,
59
- .help = "chs translation (auto, lba, none)",
60
- },{
25
- },{
61
.name = "addr",
26
.name = "addr",
62
.type = QEMU_OPT_STRING,
27
.type = QEMU_OPT_STRING,
63
.help = "pci address (virtio only)",
28
.help = "pci address (virtio only)",
64
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
29
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
65
QemuOpts *legacy_opts;
30
goto fail;
66
DriveMediaType media = MEDIA_DISK;
67
BlockInterfaceType type;
68
- int cyls, heads, secs, translation;
69
int max_devs, bus_id, unit_id, index;
70
const char *devaddr;
71
const char *werror, *rerror;
72
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
73
Error *local_err = NULL;
74
int i;
75
const char *deprecated[] = {
76
- "serial", "trans", "secs", "heads", "cyls", "addr"
77
+ "serial", "addr"
78
};
79
80
/* Change legacy command line options into QMP ones */
81
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
82
type = block_default_type;
83
}
31
}
84
32
85
- /* Geometry */
33
- /* Deprecated option boot=[on|off] */
86
- cyls = qemu_opt_get_number(legacy_opts, "cyls", 0);
34
- if (qemu_opt_get(legacy_opts, "boot") != NULL) {
87
- heads = qemu_opt_get_number(legacy_opts, "heads", 0);
35
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
88
- secs = qemu_opt_get_number(legacy_opts, "secs", 0);
36
- "ignored. Future versions will reject this parameter. Please "
89
-
37
- "update your scripts.\n");
90
- if (cyls || heads || secs) {
91
- if (cyls < 1) {
92
- error_report("invalid physical cyls number");
93
- goto fail;
94
- }
95
- if (heads < 1) {
96
- error_report("invalid physical heads number");
97
- goto fail;
98
- }
99
- if (secs < 1) {
100
- error_report("invalid physical secs number");
101
- goto fail;
102
- }
103
- }
38
- }
104
-
39
-
105
- translation = BIOS_ATA_TRANSLATION_AUTO;
40
/* Other deprecated options */
106
- value = qemu_opt_get(legacy_opts, "trans");
41
if (!qtest_enabled()) {
107
- if (value != NULL) {
42
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
108
- if (!cyls) {
43
diff --git a/qemu-doc.texi b/qemu-doc.texi
109
- error_report("'%s' trans must be used with cyls, heads and secs",
44
index XXXXXXX..XXXXXXX 100644
110
- value);
45
--- a/qemu-doc.texi
111
- goto fail;
46
+++ b/qemu-doc.texi
112
- }
47
@@ -XXX,XX +XXX,XX @@ deprecated.
113
- if (!strcmp(value, "none")) {
48
114
- translation = BIOS_ATA_TRANSLATION_NONE;
49
@section System emulator command line arguments
115
- } else if (!strcmp(value, "lba")) {
50
116
- translation = BIOS_ATA_TRANSLATION_LBA;
51
-@subsection -drive boot=on|off (since 1.3.0)
117
- } else if (!strcmp(value, "large")) {
118
- translation = BIOS_ATA_TRANSLATION_LARGE;
119
- } else if (!strcmp(value, "rechs")) {
120
- translation = BIOS_ATA_TRANSLATION_RECHS;
121
- } else if (!strcmp(value, "auto")) {
122
- translation = BIOS_ATA_TRANSLATION_AUTO;
123
- } else {
124
- error_report("'%s' invalid translation type", value);
125
- goto fail;
126
- }
127
- }
128
-
52
-
129
- if (media == MEDIA_CDROM) {
53
-The ``boot=on|off'' option to the ``-drive'' argument is
130
- if (cyls || secs || heads) {
54
-ignored. Applications should use the ``bootindex=N'' parameter
131
- error_report("CHS can't be set with media=cdrom");
55
-to set an absolute ordering between devices instead.
132
- goto fail;
133
- }
134
- }
135
-
56
-
136
/* Device address specified by bus/unit or index.
57
@subsection -tdf (since 1.3.0)
137
* If none was specified, try to find the first free one. */
58
138
bus_id = qemu_opt_get_number(legacy_opts, "bus", 0);
59
The ``-tdf'' argument is ignored. The behaviour implemented
139
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
140
dinfo = g_malloc0(sizeof(*dinfo));
141
dinfo->opts = all_opts;
142
143
- dinfo->cyls = cyls;
144
- dinfo->heads = heads;
145
- dinfo->secs = secs;
146
- dinfo->trans = translation;
147
-
148
dinfo->type = type;
149
dinfo->bus = bus_id;
150
dinfo->unit = unit_id;
151
diff --git a/hw/block/block.c b/hw/block/block.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/hw/block/block.c
154
+++ b/hw/block/block.c
155
@@ -XXX,XX +XXX,XX @@ bool blkconf_geometry(BlockConf *conf, int *ptrans,
156
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
157
Error **errp)
158
{
159
- DriveInfo *dinfo;
160
-
161
- if (!conf->cyls && !conf->heads && !conf->secs) {
162
- /* try to fall back to value set with legacy -drive cyls=... */
163
- dinfo = blk_legacy_dinfo(conf->blk);
164
- if (dinfo) {
165
- conf->cyls = dinfo->cyls;
166
- conf->heads = dinfo->heads;
167
- conf->secs = dinfo->secs;
168
- if (ptrans) {
169
- *ptrans = dinfo->trans;
170
- }
171
- }
172
- }
173
if (!conf->cyls && !conf->heads && !conf->secs) {
174
hd_geometry_guess(conf->blk,
175
&conf->cyls, &conf->heads, &conf->secs,
176
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
177
index XXXXXXX..XXXXXXX 100644
178
--- a/tests/hd-geo-test.c
179
+++ b/tests/hd-geo-test.c
180
@@ -XXX,XX +XXX,XX @@ static void setup_mbr(int img_idx, MBRcontents mbr)
181
182
static int setup_ide(int argc, char *argv[], int argv_sz,
183
int ide_idx, const char *dev, int img_idx,
184
- MBRcontents mbr, const char *opts)
185
+ MBRcontents mbr)
186
{
187
char *s1, *s2, *s3;
188
189
@@ -XXX,XX +XXX,XX @@ static int setup_ide(int argc, char *argv[], int argv_sz,
190
s3 = g_strdup(",media=cdrom");
191
}
192
argc = append_arg(argc, argv, argv_sz,
193
- g_strdup_printf("%s%s%s%s", s1, s2, s3, opts));
194
+ g_strdup_printf("%s%s%s", s1, s2, s3));
195
g_free(s1);
196
g_free(s2);
197
g_free(s3);
198
@@ -XXX,XX +XXX,XX @@ static void test_ide_mbr(bool use_device, MBRcontents mbr)
199
for (i = 0; i < backend_last; i++) {
200
cur_ide[i] = &hd_chst[i][mbr];
201
dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
202
- argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr, "");
203
+ argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
204
}
205
args = g_strjoinv(" ", argv);
206
qtest_start(args);
207
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_user(const char *dev, bool trans)
208
const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
209
210
argc = setup_common(argv, ARGV_SIZE);
211
- opts = g_strdup_printf("%s,%s%scyls=%d,heads=%d,secs=%d",
212
- dev ?: "",
213
- trans && dev ? "bios-chs-" : "",
214
- trans ? "trans=lba," : "",
215
+ opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
216
+ dev, trans ? "bios-chs-trans=lba," : "",
217
expected_chst.cyls, expected_chst.heads,
218
expected_chst.secs);
219
cur_ide[0] = &expected_chst;
220
- argc = setup_ide(argc, argv, ARGV_SIZE,
221
- 0, dev ? opts : NULL, backend_small, mbr_chs,
222
- dev ? "" : opts);
223
+ argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
224
g_free(opts);
225
args = g_strjoinv(" ", argv);
226
qtest_start(args);
227
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_user(const char *dev, bool trans)
228
}
229
230
/*
231
- * Test case: IDE device (if=ide) with explicit CHS
232
- */
233
-static void test_ide_drive_user_chs(void)
234
-{
235
- test_ide_drive_user(NULL, false);
236
-}
237
-
238
-/*
239
- * Test case: IDE device (if=ide) with explicit CHS and translation
240
- */
241
-static void test_ide_drive_user_chst(void)
242
-{
243
- test_ide_drive_user(NULL, true);
244
-}
245
-
246
-/*
247
* Test case: IDE device (if=none) with explicit CHS
248
*/
249
static void test_ide_device_user_chs(void)
250
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_cd_0(void)
251
for (i = 0; i <= backend_empty; i++) {
252
ide_idx = backend_empty - i;
253
cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
254
- argc = setup_ide(argc, argv, ARGV_SIZE,
255
- ide_idx, NULL, i, mbr_blank, "");
256
+ argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
257
}
258
args = g_strjoinv(" ", argv);
259
qtest_start(args);
260
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
261
qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
262
qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
263
qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
264
- qtest_add_func("hd-geo/ide/drive/user/chs", test_ide_drive_user_chs);
265
- qtest_add_func("hd-geo/ide/drive/user/chst", test_ide_drive_user_chst);
266
qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
267
qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
268
qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
269
diff --git a/hmp-commands.hx b/hmp-commands.hx
270
index XXXXXXX..XXXXXXX 100644
271
--- a/hmp-commands.hx
272
+++ b/hmp-commands.hx
273
@@ -XXX,XX +XXX,XX @@ ETEXI
274
.params = "[-n] [[<domain>:]<bus>:]<slot>\n"
275
"[file=file][,if=type][,bus=n]\n"
276
"[,unit=m][,media=d][,index=i]\n"
277
- "[,cyls=c,heads=h,secs=s[,trans=t]]\n"
278
"[,snapshot=on|off][,cache=on|off]\n"
279
"[,readonly=on|off][,copy-on-read=on|off]",
280
.help = "add drive to PCI storage controller",
281
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
282
index XXXXXXX..XXXXXXX 100644
283
--- a/qemu-deprecated.texi
284
+++ b/qemu-deprecated.texi
285
@@ -XXX,XX +XXX,XX @@ with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
286
(for embedded NICs). The new syntax allows different settings to be
287
provided per NIC.
288
289
-@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
290
-
291
-The drive geometry arguments are replaced by the the geometry arguments
292
-that can be specified with the ``-device'' parameter.
293
-
294
@subsection -drive serial=... (since 2.10.0)
295
296
The drive serial argument is replaced by the the serial argument
297
diff --git a/qemu-options.hx b/qemu-options.hx
298
index XXXXXXX..XXXXXXX 100644
299
--- a/qemu-options.hx
300
+++ b/qemu-options.hx
301
@@ -XXX,XX +XXX,XX @@ ETEXI
302
303
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
304
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
305
- " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
306
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
307
- " [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
308
+ " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
309
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
310
" [,readonly=on|off][,copy-on-read=on|off]\n"
311
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
312
@@ -XXX,XX +XXX,XX @@ This option defines where is connected the drive by using an index in the list
313
of available connectors of a given interface type.
314
@item media=@var{media}
315
This option defines the type of the media: disk or cdrom.
316
-@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
317
-Force disk physical geometry and the optional BIOS translation (trans=none or
318
-lba). These parameters are deprecated, use the corresponding parameters
319
-of @code{-device} instead.
320
@item snapshot=@var{snapshot}
321
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
322
(see @option{-snapshot}).
323
--
60
--
324
2.13.6
61
2.13.6
325
62
326
63
diff view generated by jsdifflib
1
This reinstates commit eae3bd1eb7c6b105d30ec06008b3bc3dfc5f45bb,
1
From: Thomas Huth <thuth@redhat.com>
2
which was temporarily reverted for the 3.0 release so that libvirt gets
2
3
some extra time to update their command lines.
3
It's been marked as deprecated since QEMU v2.10.0, and so far nobody
4
4
complained that we should keep it, so let's remove this legacy option
5
The -drive option addr was deprecated in QEMU 2.10. It's time to remove
5
now to simplify the code quite a bit.
6
it.
6
7
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>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
10
Reviewed-by: Jeff Cody <jcody@redhat.com>
11
---
11
---
12
include/sysemu/blockdev.h | 1 -
12
vl.c | 86 ++-------------------------------------------------------
13
blockdev.c | 17 +----------------
13
qemu-doc.texi | 8 ------
14
device-hotplug.c | 4 ----
14
qemu-options.hx | 19 ++-----------
15
qemu-deprecated.texi | 5 -----
15
3 files changed, 4 insertions(+), 109 deletions(-)
16
qemu-options.hx | 5 +----
16
17
5 files changed, 2 insertions(+), 30 deletions(-)
17
diff --git a/vl.c b/vl.c
18
19
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/include/sysemu/blockdev.h
19
--- a/vl.c
22
+++ b/include/sysemu/blockdev.h
20
+++ b/vl.c
23
@@ -XXX,XX +XXX,XX @@ typedef enum {
21
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
24
} BlockInterfaceType;
22
const char *boot_order = NULL;
25
23
const char *boot_once = NULL;
26
struct DriveInfo {
24
DisplayState *ds;
27
- const char *devaddr;
25
- int cyls, heads, secs, translation;
28
BlockInterfaceType type;
26
QemuOpts *opts, *machine_opts;
29
int bus;
27
- QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL;
30
int unit;
28
+ QemuOpts *icount_opts = NULL, *accel_opts = NULL;
31
diff --git a/blockdev.c b/blockdev.c
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
32
index XXXXXXX..XXXXXXX 100644
144
index XXXXXXX..XXXXXXX 100644
33
--- a/blockdev.c
145
--- a/qemu-doc.texi
34
+++ b/blockdev.c
146
+++ b/qemu-doc.texi
35
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
147
@@ -XXX,XX +XXX,XX @@ The ``--net dump'' argument is now replaced with the
36
.type = QEMU_OPT_STRING,
148
``-object filter-dump'' argument which works in combination
37
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
149
with the modern ``-netdev`` backends instead.
38
},{
150
39
- .name = "addr",
151
-@subsection -hdachs (since 2.10.0)
40
- .type = QEMU_OPT_STRING,
41
- .help = "pci address (virtio only)",
42
- },{
43
.name = "serial",
44
.type = QEMU_OPT_STRING,
45
.help = "disk serial number",
46
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
47
DriveMediaType media = MEDIA_DISK;
48
BlockInterfaceType type;
49
int max_devs, bus_id, unit_id, index;
50
- const char *devaddr;
51
const char *werror, *rerror;
52
bool read_only = false;
53
bool copy_on_read;
54
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
55
Error *local_err = NULL;
56
int i;
57
const char *deprecated[] = {
58
- "serial", "addr"
59
+ "serial"
60
};
61
62
/* Change legacy command line options into QMP ones */
63
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
64
}
65
66
/* Add virtio block device */
67
- devaddr = qemu_opt_get(legacy_opts, "addr");
68
- if (devaddr && type != IF_VIRTIO) {
69
- error_report("addr is not supported by this bus type");
70
- goto fail;
71
- }
72
-
152
-
73
if (type == IF_VIRTIO) {
153
-The ``-hdachs'' argument is now a synonym for setting
74
QemuOpts *devopts;
154
-the ``cyls'', ``heads'', ``secs'', and ``trans'' properties
75
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
155
-on the ``ide-hd'' device using the ``-device'' argument.
76
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
156
-The new syntax allows different settings to be provided
77
}
157
-per disk.
78
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
79
&error_abort);
80
- if (devaddr) {
81
- qemu_opt_set(devopts, "addr", devaddr, &error_abort);
82
- }
83
}
84
85
filename = qemu_opt_get(legacy_opts, "file");
86
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
87
dinfo->type = type;
88
dinfo->bus = bus_id;
89
dinfo->unit = unit_id;
90
- dinfo->devaddr = devaddr;
91
dinfo->serial = g_strdup(serial);
92
93
blk_set_legacy_dinfo(blk, dinfo);
94
diff --git a/device-hotplug.c b/device-hotplug.c
95
index XXXXXXX..XXXXXXX 100644
96
--- a/device-hotplug.c
97
+++ b/device-hotplug.c
98
@@ -XXX,XX +XXX,XX @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
99
if (!dinfo) {
100
goto err;
101
}
102
- if (dinfo->devaddr) {
103
- monitor_printf(mon, "Parameter addr not supported\n");
104
- goto err;
105
- }
106
107
switch (dinfo->type) {
108
case IF_NONE:
109
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
110
index XXXXXXX..XXXXXXX 100644
111
--- a/qemu-deprecated.texi
112
+++ b/qemu-deprecated.texi
113
@@ -XXX,XX +XXX,XX @@ provided per NIC.
114
The drive serial argument is replaced by the the serial argument
115
that can be specified with the ``-device'' parameter.
116
117
-@subsection -drive addr=... (since 2.10.0)
118
-
119
-The drive addr argument is replaced by the the addr argument
120
-that can be specified with the ``-device'' parameter.
121
-
158
-
122
@subsection -usbdevice (since 2.10.0)
159
@subsection -usbdevice (since 2.10.0)
123
160
124
The ``-usbdevice DEV'' argument is now a synonym for setting
161
The ``-usbdevice DEV'' argument is now a synonym for setting
125
diff --git a/qemu-options.hx b/qemu-options.hx
162
diff --git a/qemu-options.hx b/qemu-options.hx
126
index XXXXXXX..XXXXXXX 100644
163
index XXXXXXX..XXXXXXX 100644
127
--- a/qemu-options.hx
164
--- a/qemu-options.hx
128
+++ b/qemu-options.hx
165
+++ b/qemu-options.hx
129
@@ -XXX,XX +XXX,XX @@ ETEXI
166
@@ -XXX,XX +XXX,XX @@ of available connectors of a given interface type.
130
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
167
@item media=@var{media}
131
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
168
This option defines the type of the media: disk or cdrom.
132
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
169
@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
133
- " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
170
-These options have the same definition as they have in @option{-hdachs}.
134
+ " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
171
-These parameters are deprecated, use the corresponding parameters
135
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
172
+Force disk physical geometry and the optional BIOS translation (trans=none or
136
" [,readonly=on|off][,copy-on-read=on|off]\n"
173
+lba). These parameters are deprecated, use the corresponding parameters
137
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
174
of @code{-device} instead.
138
@@ -XXX,XX +XXX,XX @@ an untrusted format header.
175
@item snapshot=@var{snapshot}
139
This option specifies the serial number to assign to the device. This
176
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
140
parameter is deprecated, use the corresponding parameter of @code{-device}
177
@@ -XXX,XX +XXX,XX @@ the raw disk image you use is not written back. You can however force
141
instead.
178
the write back by pressing @key{C-a s} (@pxref{disk_images}).
142
-@item addr=@var{addr}
179
ETEXI
143
-Specify the controller's PCI address (if=virtio only). This parameter is
180
144
-deprecated, use the corresponding parameter of @code{-device} instead.
181
-DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
145
@item werror=@var{action},rerror=@var{action}
182
- "-hdachs c,h,s[,t]\n" \
146
Specify which @var{action} to take on write and read errors. Valid actions are:
183
- " force hard disk 0 physical geometry and the optional BIOS\n" \
147
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
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"
148
--
199
--
149
2.13.6
200
2.13.6
150
201
151
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: Fam Zheng <famz@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
Format drivers such as qcow2 don't allow sharing the same image between
4
two QEMU instances in order to prevent image corruptions, because of
5
metadata cache. LUKS driver don't modify metadata except for when
6
creating image, so it is safe to relax the permission. This makes
7
share-rw=on property work on virtual devices.
8
9
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
10
Signed-off-by: Fam Zheng <famz@redhat.com>
3
Signed-off-by: Fam Zheng <famz@redhat.com>
11
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
5
---
14
block/crypto.c | 4 +++-
6
include/block/block_int.h | 1 -
15
1 file changed, 3 insertions(+), 1 deletion(-)
7
block/io.c | 18 ------------------
8
2 files changed, 19 deletions(-)
16
9
17
diff --git a/block/crypto.c b/block/crypto.c
10
diff --git a/include/block/block_int.h b/include/block/block_int.h
18
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
19
--- a/block/crypto.c
12
--- a/include/block/block_int.h
20
+++ b/block/crypto.c
13
+++ b/include/block/block_int.h
21
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
14
@@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk);
22
.bdrv_probe = block_crypto_probe_luks,
15
bool blk_dev_is_medium_locked(BlockBackend *blk);
23
.bdrv_open = block_crypto_open_luks,
16
24
.bdrv_close = block_crypto_close,
17
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
25
- .bdrv_child_perm = bdrv_format_default_perms,
18
-bool bdrv_requests_pending(BlockDriverState *bs);
26
+ /* This driver doesn't modify LUKS metadata except when creating image.
19
27
+ * Allow share-rw=on as a special case. */
20
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
28
+ .bdrv_child_perm = bdrv_filter_default_perms,
21
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
29
.bdrv_co_create = block_crypto_co_create_luks,
22
diff --git a/block/io.c b/block/io.c
30
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
23
index XXXXXXX..XXXXXXX 100644
31
.bdrv_co_truncate = block_crypto_co_truncate,
24
--- a/block/io.c
25
+++ b/block/io.c
26
@@ -XXX,XX +XXX,XX @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
27
assert(old >= 1);
28
}
29
30
-/* Check if any requests are in-flight (including throttled requests) */
31
-bool bdrv_requests_pending(BlockDriverState *bs)
32
-{
33
- BdrvChild *child;
34
-
35
- if (atomic_read(&bs->in_flight)) {
36
- return true;
37
- }
38
-
39
- QLIST_FOREACH(child, &bs->children, next) {
40
- if (bdrv_requests_pending(child->bs)) {
41
- return true;
42
- }
43
- }
44
-
45
- return false;
46
-}
47
-
48
typedef struct {
49
Coroutine *co;
50
BlockDriverState *bs;
32
--
51
--
33
2.13.6
52
2.13.6
34
53
35
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
1
From: Alberto Garcia <berto@igalia.com>
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.
2
5
3
Commit 6fccbb475bc6effc313ee9481726a1748b6dae57 fixed a bug caused by
6
To keep things consistent, we also shouldn't call the block driver
4
QEMU attempting to remove a throttle group member with no pending
7
callbacks recursively.
5
requests but an active timer set. This was the result of a previous
6
bdrv_drained_begin() call processing the throttled requests but
7
leaving the timer untouched.
8
8
9
Although the commit does solve the problem, the situation shouldn't
9
A proper recursive drain version that provides an actually working
10
happen in the first place. If we try to drain a throttle group member
10
drained section for child nodes will be introduced later.
11
which has a timer set, we should cancel the timer instead of ignoring
12
it.
13
11
14
Signed-off-by: Alberto Garcia <berto@igalia.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
16
---
14
---
17
block/throttle-groups.c | 32 ++++++++++++++++++++++----------
15
block/io.c | 16 +++++++++-------
18
1 file changed, 22 insertions(+), 10 deletions(-)
16
1 file changed, 9 insertions(+), 7 deletions(-)
19
17
20
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
18
diff --git a/block/io.c b/block/io.c
21
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
22
--- a/block/throttle-groups.c
20
--- a/block/io.c
23
+++ b/block/throttle-groups.c
21
+++ b/block/io.c
24
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
25
26
static void throttle_group_obj_init(Object *obj);
27
static void throttle_group_obj_complete(UserCreatable *obj, Error **errp);
28
+static void timer_cb(ThrottleGroupMember *tgm, bool is_write);
29
30
/* The ThrottleGroup structure (with its ThrottleState) is shared
31
* among different ThrottleGroupMembers and it's independent from
32
@@ -XXX,XX +XXX,XX @@ static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
33
rd->tgm = tgm;
34
rd->is_write = is_write;
35
36
+ /* This function is called when a timer is fired or when
37
+ * throttle_group_restart_tgm() is called. Either way, there can
38
+ * be no timer pending on this tgm at this point */
39
+ assert(!timer_pending(tgm->throttle_timers.timers[is_write]));
40
+
41
co = qemu_coroutine_create(throttle_group_restart_queue_entry, rd);
42
aio_co_enter(tgm->aio_context, co);
43
}
23
}
44
24
45
void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
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)
46
{
28
{
47
+ int i;
29
BdrvChild *child, *tmp;
48
+
30
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
49
if (tgm->throttle_state) {
31
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
50
- throttle_group_restart_queue(tgm, 0);
32
bdrv_coroutine_enter(bs, data.co);
51
- throttle_group_restart_queue(tgm, 1);
33
BDRV_POLL_WHILE(bs, !data.done);
52
+ for (i = 0; i < 2; i++) {
34
53
+ QEMUTimer *t = tgm->throttle_timers.timers[i];
35
- QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
54
+ if (timer_pending(t)) {
36
- bdrv_drain_invoke(child->bs, begin);
55
+ /* If there's a pending timer on this tgm, fire it now */
37
+ if (recursive) {
56
+ timer_del(t);
38
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
57
+ timer_cb(tgm, i);
39
+ bdrv_drain_invoke(child->bs, begin, true);
58
+ } else {
59
+ /* Else run the next request from the queue manually */
60
+ throttle_group_restart_queue(tgm, i);
61
+ }
62
+ }
40
+ }
63
}
41
}
64
}
42
}
65
43
66
@@ -XXX,XX +XXX,XX @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
44
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
67
return;
45
bdrv_parent_drained_begin(bs);
68
}
46
}
69
47
70
- assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
48
- bdrv_drain_invoke(bs, true);
71
- assert(qemu_co_queue_empty(&tgm->throttled_reqs[0]));
49
+ bdrv_drain_invoke(bs, true, false);
72
- assert(qemu_co_queue_empty(&tgm->throttled_reqs[1]));
50
bdrv_drain_recurse(bs);
73
-
51
}
74
qemu_mutex_lock(&tg->lock);
52
75
for (i = 0; i < 2; i++) {
53
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
76
- if (timer_pending(tgm->throttle_timers.timers[i])) {
54
}
77
- tg->any_timer_armed[i] = false;
55
78
- schedule_next_request(tgm, i);
56
/* Re-enable things in child-to-parent order */
79
- }
57
- bdrv_drain_invoke(bs, false);
80
+ assert(tgm->pending_reqs[i] == 0);
58
+ bdrv_drain_invoke(bs, false, false);
81
+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[i]));
59
bdrv_parent_drained_end(bs);
82
+ assert(!timer_pending(tgm->throttle_timers.timers[i]));
60
aio_enable_external(bdrv_get_aio_context(bs));
83
if (tg->tokens[i] == tgm) {
61
}
84
token = throttle_group_next_tgm(tgm);
62
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
85
/* Take care of the case where this is the last tgm in the group */
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);
86
--
80
--
87
2.13.6
81
2.13.6
88
82
89
83
diff view generated by jsdifflib
New patch
1
The existing test is for bdrv_drain_all_begin/end() only. Generalise the
2
test case so that it can be run for the other variants as well. At the
3
moment this is only bdrv_drain_begin/end(), but in a while, we'll add
4
another one.
1
5
6
Also, add a backing file to the test node to test whether the operations
7
work recursively.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
tests/test-bdrv-drain.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-----
12
1 file changed, 62 insertions(+), 7 deletions(-)
13
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/test-bdrv-drain.c
17
+++ b/tests/test-bdrv-drain.c
18
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = {
19
20
.bdrv_co_drain_begin = bdrv_test_co_drain_begin,
21
.bdrv_co_drain_end = bdrv_test_co_drain_end,
22
+
23
+ .bdrv_child_perm = bdrv_format_default_perms,
24
};
25
26
static void aio_ret_cb(void *opaque, int ret)
27
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
28
*aio_ret = ret;
29
}
30
31
-static void test_drv_cb_drain_all(void)
32
+enum drain_type {
33
+ BDRV_DRAIN_ALL,
34
+ BDRV_DRAIN,
35
+};
36
+
37
+static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
38
+{
39
+ switch (drain_type) {
40
+ case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
41
+ case BDRV_DRAIN: bdrv_drained_begin(bs); break;
42
+ default: g_assert_not_reached();
43
+ }
44
+}
45
+
46
+static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
47
+{
48
+ switch (drain_type) {
49
+ case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
50
+ case BDRV_DRAIN: bdrv_drained_end(bs); break;
51
+ default: g_assert_not_reached();
52
+ }
53
+}
54
+
55
+static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
56
{
57
BlockBackend *blk;
58
- BlockDriverState *bs;
59
- BDRVTestState *s;
60
+ BlockDriverState *bs, *backing;
61
+ BDRVTestState *s, *backing_s;
62
BlockAIOCB *acb;
63
int aio_ret;
64
65
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_all(void)
66
s = bs->opaque;
67
blk_insert_bs(blk, bs, &error_abort);
68
69
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
70
+ backing_s = backing->opaque;
71
+ bdrv_set_backing_hd(bs, backing, &error_abort);
72
+
73
/* Simple bdrv_drain_all_begin/end pair, check that CBs are called */
74
g_assert_cmpint(s->drain_count, ==, 0);
75
- bdrv_drain_all_begin();
76
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
77
+
78
+ do_drain_begin(drain_type, bs);
79
+
80
g_assert_cmpint(s->drain_count, ==, 1);
81
- bdrv_drain_all_end();
82
+ g_assert_cmpint(backing_s->drain_count, ==, !!recursive);
83
+
84
+ do_drain_end(drain_type, bs);
85
+
86
g_assert_cmpint(s->drain_count, ==, 0);
87
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
88
89
/* Now do the same while a request is pending */
90
aio_ret = -EINPROGRESS;
91
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_all(void)
92
g_assert_cmpint(aio_ret, ==, -EINPROGRESS);
93
94
g_assert_cmpint(s->drain_count, ==, 0);
95
- bdrv_drain_all_begin();
96
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
97
+
98
+ do_drain_begin(drain_type, bs);
99
+
100
g_assert_cmpint(aio_ret, ==, 0);
101
g_assert_cmpint(s->drain_count, ==, 1);
102
- bdrv_drain_all_end();
103
+ g_assert_cmpint(backing_s->drain_count, ==, !!recursive);
104
+
105
+ do_drain_end(drain_type, bs);
106
+
107
g_assert_cmpint(s->drain_count, ==, 0);
108
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
109
110
+ bdrv_unref(backing);
111
bdrv_unref(bs);
112
blk_unref(blk);
113
}
114
115
+static void test_drv_cb_drain_all(void)
116
+{
117
+ test_drv_cb_common(BDRV_DRAIN_ALL, true);
118
+}
119
+
120
+static void test_drv_cb_drain(void)
121
+{
122
+ test_drv_cb_common(BDRV_DRAIN, false);
123
+}
124
+
125
int main(int argc, char **argv)
126
{
127
bdrv_init();
128
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
129
g_test_init(&argc, &argv, NULL);
130
131
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
132
+ g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
133
134
return g_test_run();
135
}
136
--
137
2.13.6
138
139
diff view generated by jsdifflib
New patch
1
This is currently only working correctly for bdrv_drain(), not for
2
bdrv_drain_all(). Leave a comment for the drain_all case, we'll address
3
it later.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 45 insertions(+)
9
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-bdrv-drain.c
13
+++ b/tests/test-bdrv-drain.c
14
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
15
test_drv_cb_common(BDRV_DRAIN, false);
16
}
17
18
+static void test_quiesce_common(enum drain_type drain_type, bool recursive)
19
+{
20
+ BlockBackend *blk;
21
+ BlockDriverState *bs, *backing;
22
+
23
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
24
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
25
+ &error_abort);
26
+ blk_insert_bs(blk, bs, &error_abort);
27
+
28
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
29
+ bdrv_set_backing_hd(bs, backing, &error_abort);
30
+
31
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
32
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
33
+
34
+ do_drain_begin(drain_type, bs);
35
+
36
+ g_assert_cmpint(bs->quiesce_counter, ==, 1);
37
+ g_assert_cmpint(backing->quiesce_counter, ==, !!recursive);
38
+
39
+ do_drain_end(drain_type, bs);
40
+
41
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
43
+
44
+ bdrv_unref(backing);
45
+ bdrv_unref(bs);
46
+ blk_unref(blk);
47
+}
48
+
49
+static void test_quiesce_drain_all(void)
50
+{
51
+ // XXX drain_all doesn't quiesce
52
+ //test_quiesce_common(BDRV_DRAIN_ALL, true);
53
+}
54
+
55
+static void test_quiesce_drain(void)
56
+{
57
+ test_quiesce_common(BDRV_DRAIN, false);
58
+}
59
+
60
int main(int argc, char **argv)
61
{
62
bdrv_init();
63
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
64
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
65
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
66
67
+ g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
68
+ g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
69
+
70
return g_test_run();
71
}
72
--
73
2.13.6
74
75
diff view generated by jsdifflib
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
From: Daniel P. Berrangé <berrange@redhat.com>
1
Block jobs must be paused if any of the involved nodes are drained.
2
2
3
When the convert command is creating an output file that needs
4
secrets, we need to ensure those secrets are passed to both the
5
blk_new_open and bdrv_create API calls.
6
7
This is done by qemu-img extracting all opts matching the name
8
suffix "key-secret". Unfortunately the code doing this was run after the
9
call to bdrv_create(), which meant the QemuOpts it was extracting
10
secrets from was now empty.
11
12
Previously this worked by luks as a bug meant the "key-secret"
13
parameters were not purged from the QemuOpts. This bug was fixed in
14
15
commit b76b4f604521e59f857d6177bc55f6f2e41fd392
16
Author: Kevin Wolf <kwolf@redhat.com>
17
Date: Thu Jan 11 16:18:08 2018 +0100
18
19
qcow2: Use visitor for options in qcow2_create()
20
21
Exposing the latent bug in qemu-img. This fix simply moves the copying
22
of secrets to before the bdrv_create() call.
23
24
Cc: qemu-stable@nongnu.org
25
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
---
4
---
28
qemu-img.c | 32 +++++++++++++++-----------------
5
tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++
29
1 file changed, 15 insertions(+), 17 deletions(-)
6
1 file changed, 121 insertions(+)
30
7
31
diff --git a/qemu-img.c b/qemu-img.c
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
32
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
33
--- a/qemu-img.c
10
--- a/tests/test-bdrv-drain.c
34
+++ b/qemu-img.c
11
+++ b/tests/test-bdrv-drain.c
35
@@ -XXX,XX +XXX,XX @@ static int img_add_key_secrets(void *opaque,
12
@@ -XXX,XX +XXX,XX @@
36
return 0;
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);
37
}
22
}
38
23
39
-static BlockBackend *img_open_new_file(const char *filename,
24
+
40
- QemuOpts *create_opts,
25
+typedef struct TestBlockJob {
41
- const char *fmt, int flags,
26
+ BlockJob common;
42
- bool writethrough, bool quiet,
27
+ bool should_complete;
43
- bool force_share)
28
+} TestBlockJob;
44
-{
29
+
45
- QDict *options = NULL;
30
+static void test_job_completed(BlockJob *job, void *opaque)
46
-
31
+{
47
- options = qdict_new();
32
+ block_job_completed(job, 0);
48
- qemu_opt_foreach(create_opts, img_add_key_secrets, options, &error_abort);
33
+}
49
-
34
+
50
- return img_open_file(filename, options, fmt, flags, writethrough, quiet,
35
+static void coroutine_fn test_job_start(void *opaque)
51
- force_share);
36
+{
52
-}
37
+ TestBlockJob *s = opaque;
53
-
38
+
54
39
+ while (!s->should_complete) {
55
static BlockBackend *img_open(bool image_opts,
40
+ block_job_sleep_ns(&s->common, 100000);
56
const char *filename,
57
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
58
BlockDriverState *out_bs;
59
QemuOpts *opts = NULL, *sn_opts = NULL;
60
QemuOptsList *create_opts = NULL;
61
+ QDict *open_opts = NULL;
62
char *options = NULL;
63
Error *local_err = NULL;
64
bool writethrough, src_writethrough, quiet = false, image_opts = false,
65
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
66
}
67
}
68
69
+ /*
70
+ * The later open call will need any decryption secrets, and
71
+ * bdrv_create() will purge "opts", so extract them now before
72
+ * they are lost.
73
+ */
74
+ if (!skip_create) {
75
+ open_opts = qdict_new();
76
+ qemu_opt_foreach(opts, img_add_key_secrets, open_opts, &error_abort);
77
+ }
41
+ }
78
+
42
+
79
if (!skip_create) {
43
+ block_job_defer_to_main_loop(&s->common, test_job_completed, NULL);
80
/* Create the new image */
44
+}
81
ret = bdrv_create(drv, out_filename, opts, &local_err);
45
+
82
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
46
+static void test_job_complete(BlockJob *job, Error **errp)
83
* That has to wait for bdrv_create to be improved
47
+{
84
* to allow filenames in option syntax
48
+ TestBlockJob *s = container_of(job, TestBlockJob, common);
85
*/
49
+ s->should_complete = true;
86
- s.target = img_open_new_file(out_filename, opts, out_fmt,
50
+}
87
- flags, writethrough, quiet, false);
51
+
88
+ s.target = img_open_file(out_filename, open_opts, out_fmt,
52
+BlockJobDriver test_job_driver = {
89
+ flags, writethrough, quiet, false);
53
+ .instance_size = sizeof(TestBlockJob),
90
+ open_opts = NULL; /* blk_new_open will have freed it */
54
+ .start = test_job_start,
91
}
55
+ .complete = test_job_complete,
92
if (!s.target) {
56
+};
93
ret = -1;
57
+
94
@@ -XXX,XX +XXX,XX @@ out:
58
+static void test_blockjob_common(enum drain_type drain_type)
95
qemu_opts_del(opts);
59
+{
96
qemu_opts_free(create_opts);
60
+ BlockBackend *blk_src, *blk_target;
97
qemu_opts_del(sn_opts);
61
+ BlockDriverState *src, *target;
98
+ qobject_unref(open_opts);
62
+ BlockJob *job;
99
blk_unref(s.target);
63
+ int ret;
100
if (s.src) {
64
+
101
for (bs_i = 0; bs_i < s.src_num; bs_i++) {
65
+ src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR,
66
+ &error_abort);
67
+ blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
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);
92
+ }
93
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
94
+ /* g_assert_true(job->paused); */
95
+ g_assert_false(job->busy); /* The job is paused */
96
+
97
+ do_drain_end(drain_type, src);
98
+
99
+ g_assert_cmpint(job->pause_count, ==, 0);
100
+ g_assert_false(job->paused);
101
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
102
+
103
+ do_drain_begin(drain_type, target);
104
+
105
+ if (drain_type == BDRV_DRAIN_ALL) {
106
+ /* bdrv_drain_all() drains both src and target, and involves an
107
+ * additional block_job_pause_all() */
108
+ g_assert_cmpint(job->pause_count, ==, 3);
109
+ } else {
110
+ g_assert_cmpint(job->pause_count, ==, 1);
111
+ }
112
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
113
+ /* g_assert_true(job->paused); */
114
+ g_assert_false(job->busy); /* The job is paused */
115
+
116
+ do_drain_end(drain_type, target);
117
+
118
+ g_assert_cmpint(job->pause_count, ==, 0);
119
+ g_assert_false(job->paused);
120
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
121
+
122
+ ret = block_job_complete_sync(job, &error_abort);
123
+ g_assert_cmpint(ret, ==, 0);
124
+
125
+ blk_unref(blk_src);
126
+ blk_unref(blk_target);
127
+ bdrv_unref(src);
128
+ bdrv_unref(target);
129
+}
130
+
131
+static void test_blockjob_drain_all(void)
132
+{
133
+ test_blockjob_common(BDRV_DRAIN_ALL);
134
+}
135
+
136
+static void test_blockjob_drain(void)
137
+{
138
+ test_blockjob_common(BDRV_DRAIN);
139
+}
140
+
141
int main(int argc, char **argv)
142
{
143
bdrv_init();
144
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
145
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
146
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
147
148
+ g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
149
+ g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
150
+
151
return g_test_run();
152
}
102
--
153
--
103
2.13.6
154
2.13.6
104
155
105
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: Alberto Garcia <berto@igalia.com>
2
3
In the throttling code after an I/O request has been completed the
4
next one is selected from a different member using a round-robin
5
algorithm. This ensures that all members get a chance to finish their
6
pending I/O requests.
7
8
However, if a group member has its I/O limits disabled (because it's
9
being drained) then we should always give it priority in order to have
10
all its pending requests finished as soon as possible.
11
12
If we don't do this we could have a member in the process of being
13
drained waiting for the throttled requests of other members, for which
14
the I/O limits still apply.
15
16
This can have additional consequences: if we're running in qtest mode
17
(with QEMU_CLOCK_VIRTUAL) then timers can only fire if we advance the
18
clock manually, so attempting to drain a block device can hang QEMU in
19
the BDRV_POLL_WHILE() loop at the end of bdrv_do_drained_begin().
20
21
Signed-off-by: Alberto Garcia <berto@igalia.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
2
---
24
block/throttle-groups.c | 9 +++++++++
3
tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
25
1 file changed, 9 insertions(+)
4
1 file changed, 57 insertions(+)
26
5
27
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
28
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
29
--- a/block/throttle-groups.c
8
--- a/tests/test-bdrv-drain.c
30
+++ b/block/throttle-groups.c
9
+++ b/tests/test-bdrv-drain.c
31
@@ -XXX,XX +XXX,XX @@ static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
10
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
32
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
11
enum drain_type {
33
ThrottleGroupMember *token, *start;
12
BDRV_DRAIN_ALL,
34
13
BDRV_DRAIN,
35
+ /* If this member has its I/O limits disabled then it means that
14
+ DRAIN_TYPE_MAX,
36
+ * it's being drained. Skip the round-robin search and return tgm
15
};
37
+ * immediately if it has pending requests. Otherwise we could be
16
38
+ * forcing it to wait for other member's throttled requests. */
17
static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
39
+ if (tgm_has_pending_reqs(tgm, is_write) &&
18
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
40
+ atomic_read(&tgm->io_limits_disabled)) {
19
test_quiesce_common(BDRV_DRAIN, false);
41
+ return tgm;
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
+ }
42
+ }
69
+ }
43
+
70
+
44
start = token = tg->tokens[is_write];
71
+ bdrv_unref(backing);
45
72
+ bdrv_unref(bs);
46
/* get next bs round in round robin style */
73
+ blk_unref(blk);
74
+}
75
+
76
77
typedef struct TestBlockJob {
78
BlockJob common;
79
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
80
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
81
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
82
83
+ g_test_add_func("/bdrv-drain/nested", test_nested);
84
+
85
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
86
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
87
47
--
88
--
48
2.13.6
89
2.13.6
49
90
50
91
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
This is in preparation for subtree drains, i.e. drained sections that
2
2
affect not only a single node, but recursively all child nodes, too.
3
When bdrv_open_inherit() opens a BlockDriverState the options QDict
3
4
can contain options for some of its children, passed in the form of
4
Calling the parent callbacks for drain is pointless when we just came
5
child-name.option=value
5
from that parent node recursively and leads to multiple increases of
6
6
bs->quiesce_counter in a single drain call. Don't do it.
7
So while each child is opened with that subset of options, those same
7
8
options remain stored in the parent BDS, leaving (at least) two copies
8
In order for this to work correctly, the parent callback must be called
9
of each one of them ("child-name.option=value" in the parent and
9
for every bdrv_drain_begin/end() call, not only for the outermost one:
10
"option=value" in the child).
10
11
11
If we have a node N with two parents A and B, recursive draining of A
12
Having the children options stored in the parent is unnecessary and it
12
should cause the quiesce_counter of B to increase because its child N is
13
can easily lead to an inconsistent state:
13
drained independently of B. If now B is recursively drained, too, A must
14
14
increase its quiesce_counter because N is drained independently of A
15
$ qemu-img create -f qcow2 hd0.qcow2 10M
15
only now, even if N is going from quiesce_counter 1 to 2.
16
$ qemu-img create -f qcow2 -b hd0.qcow2 hd1.qcow2
16
17
$ qemu-img create -f qcow2 -b hd1.qcow2 hd2.qcow2
18
19
$ $QEMU -drive file=hd2.qcow2,node-name=hd2,backing.node-name=hd1
20
21
This opens a chain of images hd0 <- hd1 <- hd2. Now let's remove hd1
22
using block_stream:
23
24
(qemu) block_stream hd2 0 hd0.qcow2
25
26
After this hd2 contains backing.node-name=hd1, which is no longer
27
correct because hd1 doesn't exist anymore.
28
29
This patch removes all children options from the parent dictionaries
30
at the end of bdrv_open_inherit() and bdrv_reopen_queue_child().
31
32
Signed-off-by: Alberto Garcia <berto@igalia.com>
33
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
---
18
---
35
block.c | 11 +++++++++++
19
include/block/block.h | 4 ++--
36
1 file changed, 11 insertions(+)
20
block.c | 13 +++++++++----
37
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:
38
diff --git a/block.c b/block.c
46
diff --git a/block.c b/block.c
39
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
40
--- a/block.c
48
--- a/block.c
41
+++ b/block.c
49
+++ b/block.c
42
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
50
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
43
BlockBackend *file = NULL;
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 {
44
BlockDriverState *bs;
133
BlockDriverState *bs;
45
BlockDriver *drv = NULL;
134
bool done;
46
+ BdrvChild *child;
135
bool begin;
47
const char *drvname;
136
+ BdrvChild *parent;
48
const char *backing;
137
} BdrvCoDrainData;
49
Error *local_err = NULL;
138
50
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
139
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
51
}
140
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
52
}
141
return waited;
53
142
}
54
+ /* Remove all children options from bs->options and bs->explicit_options */
143
55
+ QLIST_FOREACH(child, &bs->children, next) {
144
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
56
+ char *child_key_dot;
145
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
57
+ child_key_dot = g_strdup_printf("%s.", child->name);
58
+ qdict_extract_subqdict(bs->explicit_options, NULL, child_key_dot);
59
+ qdict_extract_subqdict(bs->options, NULL, child_key_dot);
60
+ g_free(child_key_dot);
61
+ }
62
+
146
+
63
bdrv_refresh_filename(bs);
147
static void bdrv_co_drain_bh_cb(void *opaque)
64
148
{
65
/* Check if any unknown options were used */
149
BdrvCoDrainData *data = opaque;
66
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
150
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
67
}
151
68
152
bdrv_dec_in_flight(bs);
69
child_key_dot = g_strdup_printf("%s.", child->name);
153
if (data->begin) {
70
+ qdict_extract_subqdict(explicit_options, NULL, child_key_dot);
154
- bdrv_drained_begin(bs);
71
qdict_extract_subqdict(options, &new_child_options, child_key_dot);
155
+ bdrv_do_drained_begin(bs, data->parent);
72
g_free(child_key_dot);
156
} else {
73
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
}
74
--
256
--
75
2.13.6
257
2.13.6
76
258
77
259
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
bdrv_drained_begin() waits for the completion of requests in the whole
2
subtree, but it only actually keeps its immediate bs parameter quiesced
3
until bdrv_drained_end().
2
4
3
.bdrv_close handler is optional after previous commit, no needs to keep
5
Add a version that keeps the whole subtree drained. As of this commit,
4
empty functions more.
6
graph changes cannot be allowed during a subtree drained section, but
7
this will be fixed soon.
5
8
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
10
---
9
block/blkreplay.c | 5 -----
11
include/block/block.h | 13 +++++++++++++
10
block/commit.c | 5 -----
12
block/io.c | 54 ++++++++++++++++++++++++++++++++++++++++-----------
11
block/copy-on-read.c | 6 ------
13
2 files changed, 56 insertions(+), 11 deletions(-)
12
block/mirror.c | 5 -----
13
block/null.c | 6 ------
14
block/raw-format.c | 5 -----
15
6 files changed, 32 deletions(-)
16
14
17
diff --git a/block/blkreplay.c b/block/blkreplay.c
15
diff --git a/include/block/block.h b/include/block/block.h
18
index XXXXXXX..XXXXXXX 100755
16
index XXXXXXX..XXXXXXX 100644
19
--- a/block/blkreplay.c
17
--- a/include/block/block.h
20
+++ b/block/blkreplay.c
18
+++ b/include/block/block.h
21
@@ -XXX,XX +XXX,XX @@ fail:
19
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
22
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;
23
}
59
}
24
60
25
-static void blkreplay_close(BlockDriverState *bs)
61
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
26
-{
62
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
27
-}
63
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
28
-
64
+ BdrvChild *parent);
29
static int64_t blkreplay_getlength(BlockDriverState *bs)
65
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
66
+ BdrvChild *parent);
67
68
static void bdrv_co_drain_bh_cb(void *opaque)
30
{
69
{
31
return bdrv_getlength(bs->file->bs);
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
32
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkreplay = {
71
33
.instance_size = 0,
72
bdrv_dec_in_flight(bs);
34
73
if (data->begin) {
35
.bdrv_open = blkreplay_open,
74
- bdrv_do_drained_begin(bs, data->parent);
36
- .bdrv_close = blkreplay_close,
75
+ bdrv_do_drained_begin(bs, data->recursive, data->parent);
37
.bdrv_child_perm = bdrv_filter_default_perms,
76
} else {
38
.bdrv_getlength = blkreplay_getlength,
77
- bdrv_do_drained_end(bs, data->parent);
39
78
+ bdrv_do_drained_end(bs, data->recursive, data->parent);
40
diff --git a/block/commit.c b/block/commit.c
79
}
41
index XXXXXXX..XXXXXXX 100644
80
42
--- a/block/commit.c
81
data->done = true;
43
+++ b/block/commit.c
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
44
@@ -XXX,XX +XXX,XX @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *opts)
45
bs->backing->bs->filename);
46
}
83
}
47
84
48
-static void bdrv_commit_top_close(BlockDriverState *bs)
85
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
49
-{
86
- bool begin, BdrvChild *parent)
50
-}
87
+ bool begin, bool recursive,
51
-
88
+ BdrvChild *parent)
52
static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c,
89
{
53
const BdrvChildRole *role,
90
BdrvCoDrainData data;
54
BlockReopenQueue *reopen_queue,
91
55
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_commit_top = {
92
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
56
.bdrv_co_preadv = bdrv_commit_top_preadv,
93
.bs = bs,
57
.bdrv_co_block_status = bdrv_co_block_status_from_backing,
94
.done = false,
58
.bdrv_refresh_filename = bdrv_commit_top_refresh_filename,
95
.begin = begin,
59
- .bdrv_close = bdrv_commit_top_close,
96
+ .recursive = recursive,
60
.bdrv_child_perm = bdrv_commit_top_child_perm,
97
.parent = parent,
61
};
98
};
62
99
bdrv_inc_in_flight(bs);
63
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
100
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
64
index XXXXXXX..XXXXXXX 100644
101
assert(data.done);
65
--- a/block/copy-on-read.c
66
+++ b/block/copy-on-read.c
67
@@ -XXX,XX +XXX,XX @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
68
}
102
}
69
103
70
104
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
71
-static void cor_close(BlockDriverState *bs)
105
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
72
-{
106
+ BdrvChild *parent)
73
-}
107
{
74
-
108
+ BdrvChild *child, *next;
75
-
109
+
76
#define PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \
110
if (qemu_in_coroutine()) {
77
| BLK_PERM_WRITE \
111
- bdrv_co_yield_to_drain(bs, true, parent);
78
| BLK_PERM_RESIZE)
112
+ bdrv_co_yield_to_drain(bs, true, recursive, parent);
79
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_copy_on_read = {
113
return;
80
.format_name = "copy-on-read",
114
}
81
115
82
.bdrv_open = cor_open,
116
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
83
- .bdrv_close = cor_close,
117
bdrv_parent_drained_begin(bs, parent);
84
.bdrv_child_perm = cor_child_perm,
118
bdrv_drain_invoke(bs, true, false);
85
119
bdrv_drain_recurse(bs);
86
.bdrv_getlength = cor_getlength,
120
+
87
diff --git a/block/mirror.c b/block/mirror.c
121
+ if (recursive) {
88
index XXXXXXX..XXXXXXX 100644
122
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
89
--- a/block/mirror.c
123
+ bdrv_do_drained_begin(child->bs, true, child);
90
+++ b/block/mirror.c
124
+ }
91
@@ -XXX,XX +XXX,XX @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
125
+ }
92
bs->backing->bs->filename);
93
}
126
}
94
127
95
-static void bdrv_mirror_top_close(BlockDriverState *bs)
128
void bdrv_drained_begin(BlockDriverState *bs)
96
-{
129
{
97
-}
130
- bdrv_do_drained_begin(bs, NULL);
98
-
131
+ bdrv_do_drained_begin(bs, false, NULL);
99
static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c,
132
+}
100
const BdrvChildRole *role,
133
+
101
BlockReopenQueue *reopen_queue,
134
+void bdrv_subtree_drained_begin(BlockDriverState *bs)
102
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_mirror_top = {
135
+{
103
.bdrv_co_flush = bdrv_mirror_top_flush,
136
+ bdrv_do_drained_begin(bs, true, NULL);
104
.bdrv_co_block_status = bdrv_co_block_status_from_backing,
105
.bdrv_refresh_filename = bdrv_mirror_top_refresh_filename,
106
- .bdrv_close = bdrv_mirror_top_close,
107
.bdrv_child_perm = bdrv_mirror_top_child_perm,
108
};
109
110
diff --git a/block/null.c b/block/null.c
111
index XXXXXXX..XXXXXXX 100644
112
--- a/block/null.c
113
+++ b/block/null.c
114
@@ -XXX,XX +XXX,XX @@ static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
115
return ret;
116
}
137
}
117
138
118
-static void null_close(BlockDriverState *bs)
139
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
119
-{
140
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
120
-}
141
+ BdrvChild *parent)
121
-
122
static int64_t null_getlength(BlockDriverState *bs)
123
{
142
{
124
BDRVNullState *s = bs->opaque;
143
+ BdrvChild *child, *next;
125
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_null_co = {
144
int old_quiesce_counter;
126
145
127
.bdrv_file_open = null_file_open,
146
if (qemu_in_coroutine()) {
128
.bdrv_parse_filename = null_co_parse_filename,
147
- bdrv_co_yield_to_drain(bs, false, parent);
129
- .bdrv_close = null_close,
148
+ bdrv_co_yield_to_drain(bs, false, recursive, parent);
130
.bdrv_getlength = null_getlength,
149
return;
131
150
}
132
.bdrv_co_preadv = null_co_preadv,
151
assert(bs->quiesce_counter > 0);
133
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_null_aio = {
152
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
134
153
if (old_quiesce_counter == 1) {
135
.bdrv_file_open = null_file_open,
154
aio_enable_external(bdrv_get_aio_context(bs));
136
.bdrv_parse_filename = null_aio_parse_filename,
155
}
137
- .bdrv_close = null_close,
156
+
138
.bdrv_getlength = null_getlength,
157
+ if (recursive) {
139
158
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
140
.bdrv_aio_preadv = null_aio_preadv,
159
+ bdrv_do_drained_end(child->bs, true, child);
141
diff --git a/block/raw-format.c b/block/raw-format.c
160
+ }
142
index XXXXXXX..XXXXXXX 100644
161
+ }
143
--- a/block/raw-format.c
144
+++ b/block/raw-format.c
145
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
146
return 0;
147
}
162
}
148
163
149
-static void raw_close(BlockDriverState *bs)
164
void bdrv_drained_end(BlockDriverState *bs)
150
-{
151
-}
152
-
153
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
154
{
165
{
155
/* smallest possible positive score so that raw is used if and only if no
166
- bdrv_do_drained_end(bs, NULL);
156
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
167
+ bdrv_do_drained_end(bs, false, NULL);
157
.bdrv_reopen_commit = &raw_reopen_commit,
168
+}
158
.bdrv_reopen_abort = &raw_reopen_abort,
169
+
159
.bdrv_open = &raw_open,
170
+void bdrv_subtree_drained_end(BlockDriverState *bs)
160
- .bdrv_close = &raw_close,
171
+{
161
.bdrv_child_perm = bdrv_filter_default_perms,
172
+ bdrv_do_drained_end(bs, true, NULL);
162
.bdrv_co_create_opts = &raw_co_create_opts,
173
}
163
.bdrv_co_preadv = &raw_co_preadv,
174
175
/*
164
--
176
--
165
2.13.6
177
2.13.6
166
178
167
179
diff view generated by jsdifflib
New patch
1
Add a subtree drain version to the existing test cases.
1
2
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
---
5
tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++-
6
1 file changed, 26 insertions(+), 1 deletion(-)
7
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
9
index XXXXXXX..XXXXXXX 100644
10
--- a/tests/test-bdrv-drain.c
11
+++ b/tests/test-bdrv-drain.c
12
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
13
enum drain_type {
14
BDRV_DRAIN_ALL,
15
BDRV_DRAIN,
16
+ BDRV_SUBTREE_DRAIN,
17
DRAIN_TYPE_MAX,
18
};
19
20
@@ -XXX,XX +XXX,XX @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
21
switch (drain_type) {
22
case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
23
case BDRV_DRAIN: bdrv_drained_begin(bs); break;
24
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break;
25
default: g_assert_not_reached();
26
}
27
}
28
@@ -XXX,XX +XXX,XX @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
29
switch (drain_type) {
30
case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
31
case BDRV_DRAIN: bdrv_drained_end(bs); break;
32
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break;
33
default: g_assert_not_reached();
34
}
35
}
36
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
37
test_drv_cb_common(BDRV_DRAIN, false);
38
}
39
40
+static void test_drv_cb_drain_subtree(void)
41
+{
42
+ test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
43
+}
44
+
45
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
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();
102
}
103
--
104
2.13.6
105
106
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.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
The previous patch fixes a problem in which draining a block device
4
with more than one throttled request can make it wait first for the
5
completion of requests in other members of the same group.
6
7
This patch updates test_remove_group_member() in iotest 093 to
8
reproduce that scenario. This updated test would hang QEMU without the
9
fix from the previous patch.
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
6
---
14
tests/qemu-iotests/093 | 19 +++++++++++--------
7
tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
15
1 file changed, 11 insertions(+), 8 deletions(-)
8
1 file changed, 59 insertions(+)
16
9
17
diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
18
index XXXXXXX..XXXXXXX 100755
11
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/093
12
--- a/tests/test-bdrv-drain.c
20
+++ b/tests/qemu-iotests/093
13
+++ b/tests/test-bdrv-drain.c
21
@@ -XXX,XX +XXX,XX @@ class ThrottleTestCase(iotests.QMPTestCase):
14
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
22
# Read 4KB from drive0. This is performed immediately.
15
*aio_ret = ret;
23
self.vm.hmp_qemu_io("drive0", "aio_read 0 4096")
16
}
24
17
25
- # Read 4KB again. The I/O limit has been exceeded so this
18
+typedef struct CallInCoroutineData {
26
+ # Read 2KB. The I/O limit has been exceeded so this
19
+ void (*entry)(void);
27
# request is throttled and a timer is set to wake it up.
20
+ bool done;
28
- self.vm.hmp_qemu_io("drive0", "aio_read 0 4096")
21
+} CallInCoroutineData;
29
+ self.vm.hmp_qemu_io("drive0", "aio_read 0 2048")
30
+
22
+
31
+ # Read 2KB again. We're still over the I/O limit so this is
23
+static coroutine_fn void call_in_coroutine_entry(void *opaque)
32
+ # request is also throttled, but no new timer is set since
24
+{
33
+ # there's already one.
25
+ CallInCoroutineData *data = opaque;
34
+ self.vm.hmp_qemu_io("drive0", "aio_read 0 2048")
26
+
35
27
+ data->entry();
36
- # Read from drive1. We're still over the I/O limit so this
28
+ data->done = true;
37
- # request is also throttled. There's no timer set in drive1
29
+}
38
- # because there's already one in drive0. Once the timer in
30
+
39
- # drive0 fires and its throttled request is processed then the
31
+static void call_in_coroutine(void (*entry)(void))
40
- # next request in the queue will be scheduled: this one.
32
+{
41
+ # Read from drive1. This request is also throttled, and no
33
+ Coroutine *co;
42
+ # timer is set in drive1 because there's already one in
34
+ CallInCoroutineData data = {
43
+ # drive0.
35
+ .entry = entry,
44
self.vm.hmp_qemu_io("drive1", "aio_read 0 4096")
36
+ .done = false,
45
37
+ };
46
# At this point only the first 4KB have been read from drive0.
38
+
47
@@ -XXX,XX +XXX,XX @@ class ThrottleTestCase(iotests.QMPTestCase):
39
+ co = qemu_coroutine_create(call_in_coroutine_entry, &data);
48
result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params)
40
+ qemu_coroutine_enter(co);
49
self.assert_qmp(result, 'return', {})
41
+ while (!data.done) {
50
42
+ aio_poll(qemu_get_aio_context(), true);
51
- # Removing the I/O limits from drive0 drains its pending request.
43
+ }
52
+ # Removing the I/O limits from drive0 drains its two pending requests.
44
+}
53
# The read request in drive1 is still throttled.
45
+
54
self.assertEqual(self.blockstats('drive0')[0], 8192)
46
enum drain_type {
55
self.assertEqual(self.blockstats('drive1')[0], 0)
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);
56
--
106
--
57
2.13.6
107
2.13.6
58
108
59
109
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Test that drain sections are correctly propagated through the graph.
2
2
3
This function extracts all options from a QDict starting with a
4
certain prefix and puts them in a new QDict.
5
6
We'll have a couple of cases where we simply want to discard those
7
options instead of copying them, and that's what this patch does.
8
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
4
---
12
qobject/block-qdict.c | 11 ++++++++---
5
tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
13
1 file changed, 8 insertions(+), 3 deletions(-)
6
1 file changed, 74 insertions(+)
14
7
15
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
16
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
17
--- a/qobject/block-qdict.c
10
--- a/tests/test-bdrv-drain.c
18
+++ b/qobject/block-qdict.c
11
+++ b/tests/test-bdrv-drain.c
19
@@ -XXX,XX +XXX,XX @@ void qdict_flatten(QDict *qdict)
12
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
20
qdict_flatten_qdict(qdict, qdict, NULL);
13
blk_unref(blk);
21
}
14
}
22
15
23
-/* extract all the src QDict entries starting by start into dst */
16
+static void test_multiparent(void)
24
+/* extract all the src QDict entries starting by start into dst.
17
+{
25
+ * If dst is NULL then the entries are simply removed from src. */
18
+ BlockBackend *blk_a, *blk_b;
26
void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
19
+ BlockDriverState *bs_a, *bs_b, *backing;
27
20
+ BDRVTestState *a_s, *b_s, *backing_s;
28
{
21
+
29
const QDictEntry *entry, *next;
22
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
30
const char *p;
23
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
31
24
+ &error_abort);
32
- *dst = qdict_new();
25
+ a_s = bs_a->opaque;
33
+ if (dst) {
26
+ blk_insert_bs(blk_a, bs_a, &error_abort);
34
+ *dst = qdict_new();
27
+
35
+ }
28
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
36
entry = qdict_first(src);
29
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
37
30
+ &error_abort);
38
while (entry != NULL) {
31
+ b_s = bs_b->opaque;
39
next = qdict_next(src, entry);
32
+ blk_insert_bs(blk_b, bs_b, &error_abort);
40
if (strstart(entry->key, start, &p)) {
33
+
41
- qdict_put_obj(*dst, p, qobject_ref(entry->value));
34
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
42
+ if (dst) {
35
+ backing_s = backing->opaque;
43
+ qdict_put_obj(*dst, p, qobject_ref(entry->value));
36
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
44
+ }
37
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
45
qdict_del(src, entry->key);
38
+
46
}
39
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
47
entry = next;
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);
48
--
100
--
49
2.13.6
101
2.13.6
50
102
51
103
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
We need to remember how many of the drain sections in which a node is
2
2
were recursive (i.e. subtree drain rather than node drain), so that they
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
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
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
10
---
6
block.c | 4 +++-
11
include/block/block.h | 2 --
7
block/snapshot.c | 4 +++-
12
include/block/block_int.h | 5 +++++
8
2 files changed, 6 insertions(+), 2 deletions(-)
13
block.c | 32 +++++++++++++++++++++++++++++---
9
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);
10
diff --git a/block.c b/block.c
53
diff --git a/block.c b/block.c
11
index XXXXXXX..XXXXXXX 100644
54
index XXXXXXX..XXXXXXX 100644
12
--- a/block.c
55
--- a/block.c
13
+++ b/block.c
56
+++ b/block.c
14
@@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs)
57
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_end(BdrvChild *child)
15
bdrv_drain(bs); /* in case flush left pending I/O */
58
bdrv_drained_end(bs);
16
59
}
17
if (bs->drv) {
60
18
- bs->drv->bdrv_close(bs);
61
+static void bdrv_child_cb_attach(BdrvChild *child)
19
+ if (bs->drv->bdrv_close) {
62
+{
20
+ bs->drv->bdrv_close(bs);
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);
21
+ }
121
+ }
22
bs->drv = NULL;
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);
23
}
131
}
24
132
25
diff --git a/block/snapshot.c b/block/snapshot.c
133
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
26
index XXXXXXX..XXXXXXX 100644
134
}
27
--- a/block/snapshot.c
135
}
28
+++ b/block/snapshot.c
136
29
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_goto(BlockDriverState *bs,
137
+ /* Attach only after starting new drained sections, so that recursive
30
qobject_unref(file_options);
138
+ * drain sections coming from @child don't get an extra .drained_begin
31
qdict_put_str(options, "file", bdrv_get_node_name(file));
139
+ * callback. */
32
140
if (child->role->attach) {
33
- drv->bdrv_close(bs);
141
child->role->attach(child);
34
+ if (drv->bdrv_close) {
142
}
35
+ drv->bdrv_close(bs);
143
diff --git a/block/io.c b/block/io.c
36
+ }
144
index XXXXXXX..XXXXXXX 100644
37
bdrv_unref_child(bs, bs->file);
145
--- a/block/io.c
38
bs->file = NULL;
146
+++ b/block/io.c
39
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.
40
--
210
--
41
2.13.6
211
2.13.6
42
212
43
213
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
2
3
A throttle group can have several members, and each one of them can
4
have several pending requests in the queue.
5
6
The requests are processed in a round-robin fashion, so the algorithm
7
decides the drive that is going to run the next request and sets a
8
timer in it. Once the timer fires and the throttled request is run
9
then the next drive from the group is selected and a new timer is set.
10
11
If the user tried to remove a drive from a group and that drive had a
12
timer set then the code was not taking care of setting up a new timer
13
in one of the remaining members of the group, freezing their I/O.
14
15
This problem was fixed in 6fccbb475bc6effc313ee9481726a1748b6dae57,
16
and this patch adds a new test case that reproduces this exact
17
scenario.
18
19
Signed-off-by: Alberto Garcia <berto@igalia.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
2
---
22
tests/qemu-iotests/093 | 52 ++++++++++++++++++++++++++++++++++++++++++++++
3
tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
23
tests/qemu-iotests/093.out | 4 ++--
4
1 file changed, 80 insertions(+)
24
2 files changed, 54 insertions(+), 2 deletions(-)
25
5
26
diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
27
index XXXXXXX..XXXXXXX 100755
7
index XXXXXXX..XXXXXXX 100644
28
--- a/tests/qemu-iotests/093
8
--- a/tests/test-bdrv-drain.c
29
+++ b/tests/qemu-iotests/093
9
+++ b/tests/test-bdrv-drain.c
30
@@ -XXX,XX +XXX,XX @@ class ThrottleTestCase(iotests.QMPTestCase):
10
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
31
limits[tk] = rate
11
blk_unref(blk_b);
32
self.do_test_throttle(ndrives, 5, limits)
12
}
33
13
34
+ # Test that removing a drive from a throttle group should not
14
+static void test_graph_change(void)
35
+ # affect the remaining members of the group.
15
+{
36
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1535914
16
+ BlockBackend *blk_a, *blk_b;
37
+ def test_remove_group_member(self):
17
+ BlockDriverState *bs_a, *bs_b, *backing;
38
+ # Create a throttle group with two drives
18
+ BDRVTestState *a_s, *b_s, *backing_s;
39
+ # and set a 4 KB/s read limit.
40
+ params = {"bps": 0,
41
+ "bps_rd": 4096,
42
+ "bps_wr": 0,
43
+ "iops": 0,
44
+ "iops_rd": 0,
45
+ "iops_wr": 0 }
46
+ self.configure_throttle(2, params)
47
+
19
+
48
+ # Read 4KB from drive0. This is performed immediately.
20
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
49
+ self.vm.hmp_qemu_io("drive0", "aio_read 0 4096")
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);
50
+
25
+
51
+ # Read 4KB again. The I/O limit has been exceeded so this
26
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
52
+ # request is throttled and a timer is set to wake it up.
27
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
53
+ self.vm.hmp_qemu_io("drive0", "aio_read 0 4096")
28
+ &error_abort);
29
+ b_s = bs_b->opaque;
30
+ blk_insert_bs(blk_b, bs_b, &error_abort);
54
+
31
+
55
+ # Read from drive1. We're still over the I/O limit so this
32
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
56
+ # request is also throttled. There's no timer set in drive1
33
+ backing_s = backing->opaque;
57
+ # because there's already one in drive0. Once the timer in
34
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
58
+ # drive0 fires and its throttled request is processed then the
59
+ # next request in the queue will be scheduled: this one.
60
+ self.vm.hmp_qemu_io("drive1", "aio_read 0 4096")
61
+
35
+
62
+ # At this point only the first 4KB have been read from drive0.
36
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
63
+ # The other requests are throttled.
37
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
64
+ self.assertEqual(self.blockstats('drive0')[0], 4096)
38
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
65
+ self.assertEqual(self.blockstats('drive1')[0], 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);
66
+
42
+
67
+ # Remove drive0 from the throttle group and disable its I/O limits.
43
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
68
+ # drive1 remains in the group with a throttled request.
44
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
69
+ params['bps_rd'] = 0
45
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
70
+ params['device'] = 'drive0'
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
71
+ result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params)
47
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
72
+ self.assert_qmp(result, 'return', {})
73
+
48
+
74
+ # Removing the I/O limits from drive0 drains its pending request.
49
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
75
+ # The read request in drive1 is still throttled.
50
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
76
+ self.assertEqual(self.blockstats('drive0')[0], 8192)
51
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
77
+ self.assertEqual(self.blockstats('drive1')[0], 0)
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);
78
+
56
+
79
+ # Advance the clock 5 seconds. This completes the request in drive1
57
+ bdrv_set_backing_hd(bs_b, NULL, &error_abort);
80
+ self.vm.qtest("clock_step %d" % (5 * nsec_per_sec))
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);
81
+
64
+
82
+ # Now all requests have been processed.
65
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
83
+ self.assertEqual(self.blockstats('drive0')[0], 8192)
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
84
+ self.assertEqual(self.blockstats('drive1')[0], 4096)
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);
85
+
72
+
86
class ThrottleTestCoroutine(ThrottleTestCase):
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
87
test_img = "null-co://"
74
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
88
75
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
89
diff --git a/tests/qemu-iotests/093.out b/tests/qemu-iotests/093.out
76
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
90
index XXXXXXX..XXXXXXX 100644
77
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
91
--- a/tests/qemu-iotests/093.out
78
+
92
+++ b/tests/qemu-iotests/093.out
79
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
93
@@ -XXX,XX +XXX,XX @@
80
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
94
-........
81
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
95
+..........
82
+ g_assert_cmpint(a_s->drain_count, ==, 0);
96
----------------------------------------------------------------------
83
+ g_assert_cmpint(b_s->drain_count, ==, 0);
97
-Ran 8 tests
84
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
98
+Ran 10 tests
85
+
99
86
+ bdrv_unref(backing);
100
OK
87
+ bdrv_unref(bs_a);
88
+ bdrv_unref(bs_b);
89
+ blk_unref(blk_a);
90
+ blk_unref(blk_b);
91
+}
92
+
93
94
typedef struct TestBlockJob {
95
BlockJob common;
96
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
97
98
g_test_add_func("/bdrv-drain/nested", test_nested);
99
g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
100
+ g_test_add_func("/bdrv-drain/graph-change", test_graph_change);
101
102
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
103
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
101
--
104
--
102
2.13.6
105
2.13.6
103
106
104
107
diff view generated by jsdifflib
1
This reinstates commit 6266e900b8083945cb766b45c124fb3c42932cb3,
1
Since commit bde70715, base is the only node that is reopened in
2
which was temporarily reverted for the 3.0 release so that libvirt gets
2
commit_start(). This means that the code, which still involves an
3
some extra time to update their command lines.
3
explicit BlockReopenQueue, can now be simplified by using bdrv_reopen().
4
5
We removed all options from the 'deprecated' array, so the code is dead
6
and can be removed as well.
7
4
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
Reviewed-by: Fam Zheng <famz@redhat.com>
10
---
7
---
11
blockdev.c | 12 ------------
8
block/commit.c | 8 +-------
12
1 file changed, 12 deletions(-)
9
1 file changed, 1 insertion(+), 7 deletions(-)
13
10
14
diff --git a/blockdev.c b/blockdev.c
11
diff --git a/block/commit.c b/block/commit.c
15
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
16
--- a/blockdev.c
13
--- a/block/commit.c
17
+++ b/blockdev.c
14
+++ b/block/commit.c
18
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
15
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
19
const char *filename;
16
const char *filter_node_name, Error **errp)
20
Error *local_err = NULL;
17
{
21
int i;
18
CommitBlockJob *s;
22
- const char *deprecated[] = {
19
- BlockReopenQueue *reopen_queue = NULL;
23
- };
20
int orig_base_flags;
24
21
BlockDriverState *iter;
25
/* Change legacy command line options into QMP ones */
22
BlockDriverState *commit_top_bs = NULL;
26
static const struct {
23
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
27
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
24
/* convert base to r/w, if necessary */
28
goto fail;
25
orig_base_flags = bdrv_get_flags(base);
29
}
26
if (!(orig_base_flags & BDRV_O_RDWR)) {
30
27
- reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
31
- /* Other deprecated options */
28
- orig_base_flags | BDRV_O_RDWR);
32
- if (!qtest_enabled()) {
33
- for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
34
- if (qemu_opt_get(legacy_opts, deprecated[i]) != NULL) {
35
- error_report("'%s' is deprecated, please use the corresponding "
36
- "option of '-device' instead", deprecated[i]);
37
- }
38
- }
39
- }
29
- }
40
-
30
-
41
/* Media type */
31
- if (reopen_queue) {
42
value = qemu_opt_get(legacy_opts, "media");
32
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
43
if (value) {
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;
44
--
37
--
45
2.13.6
38
2.13.6
46
39
47
40
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The bdrv_reopen*() implementation doesn't like it if the graph is
2
changed between queuing nodes for reopen and actually reopening them
3
(one of the reasons is that queuing can be recursive).
2
4
3
If bdrv_reopen() succeeds then bs->explicit_options is updated with
5
So instead of draining the device only in bdrv_reopen_multiple(),
4
the new values, but bs->options never changes.
6
require that callers already drained all affected nodes, and assert this
7
in bdrv_reopen_queue().
5
8
6
Here's an example:
7
8
{ "execute": "blockdev-add",
9
"arguments": {
10
"driver": "qcow2",
11
"node-name": "hd0",
12
"overlap-check": "all",
13
"file": {
14
"driver": "file",
15
"filename": "hd0.qcow2"
16
}
17
}
18
}
19
20
After this, both bs->options and bs->explicit_options contain
21
"overlap-check": "all".
22
23
Now let's change that using qemu-io's reopen command:
24
25
(qemu) qemu-io hd0 "reopen -o overlap-check=none"
26
27
After this, bs->explicit_options contains the new value but
28
bs->options still keeps the old one.
29
30
This patch updates bs->options after a BDS has been successfully
31
reopened.
32
33
Signed-off-by: Alberto Garcia <berto@igalia.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
35
---
11
---
36
block.c | 15 ++++++++++++++-
12
block.c | 23 ++++++++++++++++-------
37
1 file changed, 14 insertions(+), 1 deletion(-)
13
block/replication.c | 6 ++++++
14
qemu-io-cmds.c | 3 +++
15
3 files changed, 25 insertions(+), 7 deletions(-)
38
16
39
diff --git a/block.c b/block.c
17
diff --git a/block.c b/block.c
40
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
41
--- a/block.c
19
--- a/block.c
42
+++ b/block.c
20
+++ b/block.c
21
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
22
* returns a pointer to bs_queue, which is either the newly allocated
23
* bs_queue, or the existing bs_queue being used.
24
*
25
+ * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple().
26
*/
27
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
28
BlockDriverState *bs,
29
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
30
BdrvChild *child;
31
QDict *old_options, *explicit_options;
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;
43
@@ -XXX,XX +XXX,XX @@ cleanup:
63
@@ -XXX,XX +XXX,XX @@ cleanup:
44
bdrv_reopen_abort(&bs_entry->state);
45
}
46
qobject_unref(bs_entry->state.explicit_options);
47
+ qobject_unref(bs_entry->state.options);
48
}
49
- qobject_unref(bs_entry->state.options);
50
g_free(bs_entry);
51
}
64
}
52
g_free(bs_queue);
65
g_free(bs_queue);
53
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
66
54
Error *local_err = NULL;
67
- bdrv_drain_all_end();
55
BlockDriver *drv;
68
-
56
QemuOpts *opts;
57
+ QDict *orig_reopen_opts;
58
const char *value;
59
bool read_only;
60
61
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
62
assert(reopen_state->bs->drv != NULL);
63
drv = reopen_state->bs->drv;
64
65
+ /* This function and each driver's bdrv_reopen_prepare() remove
66
+ * entries from reopen_state->options as they are processed, so
67
+ * we need to make a copy of the original QDict. */
68
+ orig_reopen_opts = qdict_clone_shallow(reopen_state->options);
69
+
70
/* Process generic block layer options */
71
opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
72
qemu_opts_absorb_qdict(opts, reopen_state->options, &local_err);
73
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
74
75
ret = 0;
76
77
+ /* Restore the original reopen_state->options QDict */
78
+ qobject_unref(reopen_state->options);
79
+ reopen_state->options = qobject_ref(orig_reopen_opts);
80
+
81
error:
82
qemu_opts_del(opts);
83
+ qobject_unref(orig_reopen_opts);
84
return ret;
69
return ret;
85
}
70
}
86
71
87
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
72
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
88
73
{
89
/* set BDS specific flags now */
74
int ret = -1;
90
qobject_unref(bs->explicit_options);
75
Error *local_err = NULL;
91
+ qobject_unref(bs->options);
76
- BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
92
77
+ BlockReopenQueue *queue;
93
bs->explicit_options = reopen_state->explicit_options;
78
94
+ bs->options = reopen_state->options;
79
+ bdrv_subtree_drained_begin(bs);
95
bs->open_flags = reopen_state->flags;
80
+
96
bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
81
+ queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
97
82
ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err);
83
if (local_err != NULL) {
84
error_propagate(errp, local_err);
85
}
86
+
87
+ bdrv_subtree_drained_end(bs);
88
+
89
return ret;
90
}
91
92
diff --git a/block/replication.c b/block/replication.c
93
index XXXXXXX..XXXXXXX 100644
94
--- a/block/replication.c
95
+++ b/block/replication.c
96
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
97
new_secondary_flags = s->orig_secondary_flags;
98
}
99
100
+ bdrv_subtree_drained_begin(s->hidden_disk->bs);
101
+ bdrv_subtree_drained_begin(s->secondary_disk->bs);
102
+
103
if (orig_hidden_flags != new_hidden_flags) {
104
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
105
new_hidden_flags);
106
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
107
reopen_queue, &local_err);
108
error_propagate(errp, local_err);
109
}
110
+
111
+ bdrv_subtree_drained_end(s->hidden_disk->bs);
112
+ bdrv_subtree_drained_end(s->secondary_disk->bs);
113
}
114
115
static void backup_job_cleanup(BlockDriverState *bs)
116
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
117
index XXXXXXX..XXXXXXX 100644
118
--- a/qemu-io-cmds.c
119
+++ b/qemu-io-cmds.c
120
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
121
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
122
qemu_opts_reset(&reopen_opts);
123
124
+ bdrv_subtree_drained_begin(bs);
125
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
126
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
127
+ bdrv_subtree_drained_end(bs);
128
+
129
if (local_err) {
130
error_report_err(local_err);
131
} else {
98
--
132
--
99
2.13.6
133
2.13.6
100
134
101
135
diff view generated by jsdifflib