1
The following changes since commit 89ea03a7dc83ca36b670ba7f787802791fcb04b1:
1
The following changes since commit 281f327487c9c9b1599f93c589a408bbf4a651b8:
2
2
3
Merge remote-tracking branch 'remotes/huth-gitlab/tags/m68k-pull-2019-09-07' into staging (2019-09-09 09:48:34 +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 65f9f0c2a53b1572043501bb4e99500914e88cc6:
9
for you to fetch changes up to 1a63a907507fbbcfaee3f622907ec244b7eabda8:
10
10
11
qcow2: Stop overwriting compressed clusters one by one (2019-09-12 11:26:59 +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
- qcow2: Allow overwriting multiple compressed clusters at once for
17
better performance
18
- nfs: add support for nfs_umount
19
- file-posix: write_zeroes fixes
20
- qemu-io, blockdev-create, pr-manager: Fix crashes and memory leaks
21
- qcow2: Fix the calculation of the maximum L2 cache size
22
- vpc: Fix return code for vpc_co_create()
23
- blockjob: Code cleanup
24
- iotests improvements (e.g. for use with valgrind)
25
15
26
----------------------------------------------------------------
16
----------------------------------------------------------------
27
Alberto Garcia (2):
17
Doug Gale (1):
28
qcow2: Fix the calculation of the maximum L2 cache size
18
nvme: Add tracing
29
qcow2: Stop overwriting compressed clusters one by one
30
19
31
Andrey Shinkevich (6):
20
Edgar Kaziakhmedov (1):
32
iotests: allow Valgrind checking all QEMU processes
21
qcow2: get rid of qcow2_backing_read1 routine
33
iotests: exclude killed processes from running under Valgrind
34
iotests: Add casenotrun report to bash tests
35
iotests: Valgrind fails with nonexistent directory
36
iotests: extended timeout under Valgrind
37
iotests: extend sleeping time under Valgrind
38
22
39
Kevin Wolf (2):
23
Fam Zheng (2):
40
file-posix: Fix has_write_zeroes after NO_FALLBACK
24
block: Open backing image in force share mode for size probe
41
qemu-io: Don't leak pattern file in error path
25
block: Remove unused bdrv_requests_pending
42
26
43
Markus Armbruster (1):
27
John Snow (1):
44
pr-manager: Fix invalid g_free() crash bug
28
iotests: fix 197 for vpc
45
29
46
Max Reitz (7):
30
Kevin Wolf (27):
47
block/file-posix: Reduce xfsctl() use
31
block: Formats don't need CONSISTENT_READ with NO_IO
48
iotests: Test reverse sub-cluster qcow2 writes
32
block: Make bdrv_drain_invoke() recursive
49
vpc: Return 0 from vpc_co_create() on success
33
block: Call .drain_begin only once in bdrv_drain_all_begin()
50
iotests: Add supported protocols to execute_test()
34
test-bdrv-drain: Test BlockDriver callbacks for drain
51
iotests: Restrict file Python tests to file
35
block: bdrv_drain_recurse(): Remove unused begin parameter
52
iotests: Restrict nbd Python tests to nbd
36
block: Don't wait for requests in bdrv_drain*_end()
53
iotests: Test blockdev-create for vpc
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
54
58
55
Peter Lieven (1):
59
Thomas Huth (3):
56
block/nfs: add support for nfs_umount
60
block: Remove the obsolete -drive boot=on|off parameter
61
block: Remove the deprecated -hdachs option
62
block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter
57
63
58
Philippe Mathieu-Daudé (1):
64
qapi/block-core.json | 4 +
59
block/create: Do not abort if a block driver is not available
65
block/qcow2.h | 3 -
66
include/block/block.h | 15 +-
67
include/block/block_int.h | 6 +-
68
block.c | 75 ++++-
69
block/commit.c | 8 +-
70
block/io.c | 164 +++++++---
71
block/qcow2.c | 51 +--
72
block/replication.c | 6 +
73
blockdev.c | 11 -
74
blockjob.c | 22 +-
75
hmp.c | 6 -
76
hw/block/nvme.c | 349 +++++++++++++++++----
77
qemu-io-cmds.c | 3 +
78
tests/test-bdrv-drain.c | 651 +++++++++++++++++++++++++++++++++++++++
79
vl.c | 86 +-----
80
hw/block/trace-events | 93 ++++++
81
qemu-doc.texi | 29 +-
82
qemu-options.hx | 19 +-
83
tests/Makefile.include | 2 +
84
tests/qemu-iotests/197 | 4 +
85
tests/qemu-iotests/common.filter | 3 +-
86
22 files changed, 1294 insertions(+), 316 deletions(-)
87
create mode 100644 tests/test-bdrv-drain.c
60
88
61
Vladimir Sementsov-Ogievskiy (2):
62
job: drop job_drain
63
iotests: skip 232 when run tests as root
64
65
include/block/blockjob_int.h | 19 ------
66
include/qemu/job.h | 13 ----
67
block/backup.c | 19 +-----
68
block/commit.c | 1 -
69
block/create.c | 6 +-
70
block/file-posix.c | 83 ++---------------------
71
block/mirror.c | 28 +-------
72
block/nfs.c | 5 +-
73
block/qcow2-cluster.c | 8 +--
74
block/qcow2.c | 6 +-
75
block/stream.c | 1 -
76
block/vpc.c | 3 +-
77
blockjob.c | 13 ----
78
job.c | 12 +---
79
qemu-io-cmds.c | 4 ++
80
scsi/pr-manager.c | 1 -
81
tests/test-bdrv-drain.c | 3 -
82
tests/test-block-iothread.c | 1 -
83
tests/test-blockjob-txn.c | 1 -
84
tests/test-blockjob.c | 2 -
85
tests/qemu-iotests/028 | 6 +-
86
tests/qemu-iotests/030 | 3 +-
87
tests/qemu-iotests/039 | 5 ++
88
tests/qemu-iotests/039.out | 30 ++-------
89
tests/qemu-iotests/040 | 3 +-
90
tests/qemu-iotests/041 | 3 +-
91
tests/qemu-iotests/044 | 3 +-
92
tests/qemu-iotests/045 | 3 +-
93
tests/qemu-iotests/051 | 4 ++
94
tests/qemu-iotests/055 | 3 +-
95
tests/qemu-iotests/056 | 3 +-
96
tests/qemu-iotests/057 | 3 +-
97
tests/qemu-iotests/061 | 2 +
98
tests/qemu-iotests/061.out | 12 +---
99
tests/qemu-iotests/065 | 3 +-
100
tests/qemu-iotests/096 | 3 +-
101
tests/qemu-iotests/118 | 3 +-
102
tests/qemu-iotests/124 | 3 +-
103
tests/qemu-iotests/129 | 3 +-
104
tests/qemu-iotests/132 | 3 +-
105
tests/qemu-iotests/137 | 1 +
106
tests/qemu-iotests/137.out | 6 +-
107
tests/qemu-iotests/139 | 3 +-
108
tests/qemu-iotests/147 | 5 +-
109
tests/qemu-iotests/148 | 3 +-
110
tests/qemu-iotests/151 | 3 +-
111
tests/qemu-iotests/152 | 3 +-
112
tests/qemu-iotests/155 | 3 +-
113
tests/qemu-iotests/163 | 3 +-
114
tests/qemu-iotests/165 | 3 +-
115
tests/qemu-iotests/169 | 3 +-
116
tests/qemu-iotests/183 | 9 ++-
117
tests/qemu-iotests/192 | 6 +-
118
tests/qemu-iotests/196 | 3 +-
119
tests/qemu-iotests/199 | 3 +-
120
tests/qemu-iotests/205 | 3 +-
121
tests/qemu-iotests/232 | 6 ++
122
tests/qemu-iotests/245 | 3 +-
123
tests/qemu-iotests/247 | 6 +-
124
tests/qemu-iotests/257 | 3 +-
125
tests/qemu-iotests/265 | 67 ++++++++++++++++++
126
tests/qemu-iotests/265.out | 6 ++
127
tests/qemu-iotests/266 | 153 ++++++++++++++++++++++++++++++++++++++++++
128
tests/qemu-iotests/266.out | 137 +++++++++++++++++++++++++++++++++++++
129
tests/qemu-iotests/common.rc | 105 ++++++++++++++++++++++++-----
130
tests/qemu-iotests/group | 2 +
131
tests/qemu-iotests/iotests.py | 4 +-
132
67 files changed, 590 insertions(+), 292 deletions(-)
133
create mode 100755 tests/qemu-iotests/265
134
create mode 100644 tests/qemu-iotests/265.out
135
create mode 100755 tests/qemu-iotests/266
136
create mode 100644 tests/qemu-iotests/266.out
137
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.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
To synchronize the time when QEMU is running longer under the Valgrind,
5
As this permission is geared towards whether the guest-visible data is
4
increase the sleeping time in the test 247.
6
consistent, and has no impact on whether the metadata is sane, and
7
'qemu-img info' does not read guest-visible data (except for the raw
8
format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there
9
is not going to be any guest I/O performed, regardless of image format.
5
10
6
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
12
---
11
tests/qemu-iotests/247 | 6 +++++-
13
block.c | 6 +++++-
12
1 file changed, 5 insertions(+), 1 deletion(-)
14
1 file changed, 5 insertions(+), 1 deletion(-)
13
15
14
diff --git a/tests/qemu-iotests/247 b/tests/qemu-iotests/247
16
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100755
17
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/247
18
--- a/block.c
17
+++ b/tests/qemu-iotests/247
19
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ TEST_IMG="$TEST_IMG.4" _make_test_img $size
20
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
19
{"execute":"block-commit",
21
assert(role == &child_backing || role == &child_file);
20
"arguments":{"device":"format-4", "top-node": "format-2", "base-node":"format-0", "job-id":"job0"}}
22
21
EOF
23
if (!backing) {
22
-sleep 1
24
+ int flags = bdrv_reopen_get_flags(reopen_queue, bs);
23
+if [ "${VALGRIND_QEMU}" == "y" ]; then
25
+
24
+ sleep 10
26
/* Apart from the modifications below, the same permissions are
25
+else
27
* forwarded and left alone as for filters */
26
+ sleep 1
28
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
27
+fi
29
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
28
echo '{"execute":"quit"}'
30
29
) | $QEMU -qmp stdio -nographic -nodefaults \
31
/* bs->file always needs to be consistent because of the metadata. We
30
-blockdev file,node-name=file-0,filename=$TEST_IMG.0,auto-read-only=on \
32
* can never allow other users to resize or write to it. */
33
- perm |= BLK_PERM_CONSISTENT_READ;
34
+ if (!(flags & BDRV_O_NO_IO)) {
35
+ perm |= BLK_PERM_CONSISTENT_READ;
36
+ }
37
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
38
} else {
39
/* We want consistent read from backing files if the parent needs it.
31
--
40
--
32
2.20.1
41
2.13.6
33
42
34
43
diff view generated by jsdifflib
New patch
1
From: John Snow <jsnow@redhat.com>
1
2
3
VPC has some difficulty creating geometries of particular size.
4
However, we can indeed force it to use a literal one, so let's
5
do that for the sake of test 197, which is testing some specific
6
offsets.
7
8
Signed-off-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Lukáš Doktor <ldoktor@redhat.com>
13
---
14
tests/qemu-iotests/197 | 4 ++++
15
tests/qemu-iotests/common.filter | 3 ++-
16
2 files changed, 6 insertions(+), 1 deletion(-)
17
18
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/197
21
+++ b/tests/qemu-iotests/197
22
@@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ==='
23
echo
24
25
# Prep the images
26
+# VPC rounds image sizes to a specific geometry, force a specific size.
27
+if [ "$IMGFMT" = "vpc" ]; then
28
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
29
+fi
30
_make_test_img 4G
31
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
32
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
33
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
34
index XXXXXXX..XXXXXXX 100644
35
--- a/tests/qemu-iotests/common.filter
36
+++ b/tests/qemu-iotests/common.filter
37
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
38
-e "s# log_size=[0-9]\\+##g" \
39
-e "s# refcount_bits=[0-9]\\+##g" \
40
-e "s# key-secret=[a-zA-Z0-9]\\+##g" \
41
- -e "s# iter-time=[0-9]\\+##g"
42
+ -e "s# iter-time=[0-9]\\+##g" \
43
+ -e "s# force_size=\\(on\\|off\\)##g"
44
}
45
46
_filter_img_info()
47
--
48
2.13.6
49
50
diff view generated by jsdifflib
New patch
1
This change separates bdrv_drain_invoke(), which calls the BlockDriver
2
drain callbacks, from bdrv_drain_recurse(). Instead, the function
3
performs its own recursion now.
1
4
5
One reason for this is that bdrv_drain_recurse() can be called multiple
6
times by bdrv_drain_all_begin(), but the callbacks may only be called
7
once. The separation is necessary to fix this bug.
8
9
The other reason is that we intend to go to a model where we call all
10
driver callbacks first, and only then start polling. This is not fully
11
achieved yet with this patch, as bdrv_drain_invoke() contains a
12
BDRV_POLL_WHILE() loop for the block driver callbacks, which can still
13
call callbacks for any unrelated event. It's a step in this direction
14
anyway.
15
16
Cc: qemu-stable@nongnu.org
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
19
---
20
block/io.c | 14 +++++++++++---
21
1 file changed, 11 insertions(+), 3 deletions(-)
22
23
diff --git a/block/io.c b/block/io.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/io.c
26
+++ b/block/io.c
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
28
bdrv_wakeup(bs);
29
}
30
31
+/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
32
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
33
{
34
+ BdrvChild *child, *tmp;
35
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
36
37
if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) ||
38
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
39
data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data);
40
bdrv_coroutine_enter(bs, data.co);
41
BDRV_POLL_WHILE(bs, !data.done);
42
+
43
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
44
+ bdrv_drain_invoke(child->bs, begin);
45
+ }
46
}
47
48
static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
49
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
50
BdrvChild *child, *tmp;
51
bool waited;
52
53
- /* Ensure any pending metadata writes are submitted to bs->file. */
54
- bdrv_drain_invoke(bs, begin);
55
-
56
/* Wait for drained requests to finish */
57
waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
58
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
60
bdrv_parent_drained_begin(bs);
61
}
62
63
+ bdrv_drain_invoke(bs, true);
64
bdrv_drain_recurse(bs, true);
65
}
66
67
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
68
}
69
70
bdrv_parent_drained_end(bs);
71
+ bdrv_drain_invoke(bs, false);
72
bdrv_drain_recurse(bs, false);
73
aio_enable_external(bdrv_get_aio_context(bs));
74
}
75
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
76
aio_context_acquire(aio_context);
77
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
78
if (aio_context == bdrv_get_aio_context(bs)) {
79
+ /* FIXME Calling this multiple times is wrong */
80
+ bdrv_drain_invoke(bs, true);
81
waited |= bdrv_drain_recurse(bs, true);
82
}
83
}
84
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
85
aio_context_acquire(aio_context);
86
aio_enable_external(aio_context);
87
bdrv_parent_drained_end(bs);
88
+ bdrv_drain_invoke(bs, false);
89
bdrv_drain_recurse(bs, false);
90
aio_context_release(aio_context);
91
}
92
--
93
2.13.6
94
95
diff view generated by jsdifflib
New patch
1
bdrv_drain_all_begin() used to call the .bdrv_co_drain_begin() driver
2
callback inside its polling loop. This means that how many times it got
3
called for each node depended on long it had to poll the event loop.
1
4
5
This is obviously not right and results in nodes that stay drained even
6
after bdrv_drain_all_end(), which calls .bdrv_co_drain_begin() once per
7
node.
8
9
Fix bdrv_drain_all_begin() to call the callback only once, too.
10
11
Cc: qemu-stable@nongnu.org
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
15
block/io.c | 3 +--
16
1 file changed, 1 insertion(+), 2 deletions(-)
17
18
diff --git a/block/io.c b/block/io.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/io.c
21
+++ b/block/io.c
22
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
23
aio_context_acquire(aio_context);
24
bdrv_parent_drained_begin(bs);
25
aio_disable_external(aio_context);
26
+ bdrv_drain_invoke(bs, true);
27
aio_context_release(aio_context);
28
29
if (!g_slist_find(aio_ctxs, aio_context)) {
30
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
31
aio_context_acquire(aio_context);
32
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
33
if (aio_context == bdrv_get_aio_context(bs)) {
34
- /* FIXME Calling this multiple times is wrong */
35
- bdrv_drain_invoke(bs, true);
36
waited |= bdrv_drain_recurse(bs, true);
37
}
38
}
39
--
40
2.13.6
41
42
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
This adds a test case that the BlockDriver callbacks for drain are
2
called in bdrv_drained_all_begin/end(), and that both of them are called
3
exactly once.
2
4
3
This exercises the regression introduced in commit
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
50ba5b2d994853b38fed10e0841b119da0f8b8e5. On my machine, it has close
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
to a 50 % false-negative rate, but that should still be sufficient to
7
Reviewed-by: Eric Blake <eblake@redhat.com>
6
test the fix.
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
7
13
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
9
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
11
Tested-by: Stefano Garzarella <sgarzare@redhat.com>
12
Tested-by: John Snow <jsnow@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
tests/qemu-iotests/265 | 67 ++++++++++++++++++++++++++++++++++++++
16
tests/qemu-iotests/265.out | 6 ++++
17
tests/qemu-iotests/group | 1 +
18
3 files changed, 74 insertions(+)
19
create mode 100755 tests/qemu-iotests/265
20
create mode 100644 tests/qemu-iotests/265.out
21
22
diff --git a/tests/qemu-iotests/265 b/tests/qemu-iotests/265
23
new file mode 100755
24
index XXXXXXX..XXXXXXX
25
--- /dev/null
26
+++ b/tests/qemu-iotests/265
27
@@ -XXX,XX +XXX,XX @@
28
+#!/usr/bin/env bash
29
+#
30
+# Test reverse-ordered qcow2 writes on a sub-cluster level
31
+#
32
+# Copyright (C) 2019 Red Hat, Inc.
33
+#
34
+# This program is free software; you can redistribute it and/or modify
35
+# it under the terms of the GNU General Public License as published by
36
+# the Free Software Foundation; either version 2 of the License, or
37
+# (at your option) any later version.
38
+#
39
+# This program is distributed in the hope that it will be useful,
40
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
41
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42
+# GNU General Public License for more details.
43
+#
44
+# You should have received a copy of the GNU General Public License
45
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
46
+#
47
+
48
+seq=$(basename $0)
49
+echo "QA output created by $seq"
50
+
51
+status=1    # failure is the default!
52
+
53
+_cleanup()
54
+{
55
+ _cleanup_test_img
56
+}
57
+trap "_cleanup; exit \$status" 0 1 2 3 15
58
+
59
+# get standard environment, filters and checks
60
+. ./common.rc
61
+. ./common.filter
62
+
63
+# qcow2-specific test
64
+_supported_fmt qcow2
65
+_supported_proto file
66
+_supported_os Linux
67
+
68
+echo '--- Writing to the image ---'
69
+
70
+# Reduce cluster size so we get more and quicker I/O
71
+IMGOPTS='cluster_size=4096' _make_test_img 1M
72
+(for ((kb = 1024 - 4; kb >= 0; kb -= 4)); do \
73
+ echo "aio_write -P 42 $((kb + 1))k 2k"; \
74
+ done) \
75
+ | $QEMU_IO "$TEST_IMG" > /dev/null
76
+
77
+echo '--- Verifying its content ---'
78
+
79
+(for ((kb = 0; kb < 1024; kb += 4)); do \
80
+ echo "read -P 0 ${kb}k 1k"; \
81
+ echo "read -P 42 $((kb + 1))k 2k"; \
82
+ echo "read -P 0 $((kb + 3))k 1k"; \
83
+ done) \
84
+ | $QEMU_IO "$TEST_IMG" | _filter_qemu_io | grep 'verification'
85
+
86
+# Status of qemu-io
87
+if [ ${PIPESTATUS[1]} = 0 ]; then
88
+ echo 'Content verified.'
89
+fi
90
+
91
+# success, all done
92
+echo "*** done"
93
+rm -f $seq.full
94
+status=0
95
diff --git a/tests/qemu-iotests/265.out b/tests/qemu-iotests/265.out
96
new file mode 100644
15
new file mode 100644
97
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
98
--- /dev/null
17
--- /dev/null
99
+++ b/tests/qemu-iotests/265.out
18
+++ b/tests/test-bdrv-drain.c
100
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
101
+QA output created by 265
20
+/*
102
+--- Writing to the image ---
21
+ * Block node draining tests
103
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
22
+ *
104
+--- Verifying its content ---
23
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
105
+Content verified.
24
+ *
106
+*** done
25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
107
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
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
108
index XXXXXXX..XXXXXXX 100644
158
index XXXXXXX..XXXXXXX 100644
109
--- a/tests/qemu-iotests/group
159
--- a/tests/Makefile.include
110
+++ b/tests/qemu-iotests/group
160
+++ b/tests/Makefile.include
111
@@ -XXX,XX +XXX,XX @@
161
@@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c
112
257 rw
162
gcov-files-test-hbitmap-y = util/hbitmap.c
113
258 rw quick
163
check-unit-y += tests/test-hbitmap$(EXESUF)
114
262 rw quick migration
164
gcov-files-test-hbitmap-y = blockjob.c
115
+265 rw auto quick
165
+check-unit-y += tests/test-bdrv-drain$(EXESUF)
166
check-unit-y += tests/test-blockjob$(EXESUF)
167
check-unit-y += tests/test-blockjob-txn$(EXESUF)
168
check-unit-y += tests/test-x86-cpuid$(EXESUF)
169
@@ -XXX,XX +XXX,XX @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
170
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
171
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
172
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
173
+tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
174
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
175
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
176
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
116
--
177
--
117
2.20.1
178
2.13.6
118
179
119
180
diff view generated by jsdifflib
New patch
1
Now that the bdrv_drain_invoke() calls are pulled up to the callers of
2
bdrv_drain_recurse(), the 'begin' parameter isn't needed any more.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/io.c | 12 ++++++------
8
1 file changed, 6 insertions(+), 6 deletions(-)
9
10
diff --git a/block/io.c b/block/io.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/io.c
13
+++ b/block/io.c
14
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
15
}
16
}
17
18
-static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
19
+static bool bdrv_drain_recurse(BlockDriverState *bs)
20
{
21
BdrvChild *child, *tmp;
22
bool waited;
23
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
24
*/
25
bdrv_ref(bs);
26
}
27
- waited |= bdrv_drain_recurse(bs, begin);
28
+ waited |= bdrv_drain_recurse(bs);
29
if (in_main_loop) {
30
bdrv_unref(bs);
31
}
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
33
}
34
35
bdrv_drain_invoke(bs, true);
36
- bdrv_drain_recurse(bs, true);
37
+ bdrv_drain_recurse(bs);
38
}
39
40
void bdrv_drained_end(BlockDriverState *bs)
41
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
42
43
bdrv_parent_drained_end(bs);
44
bdrv_drain_invoke(bs, false);
45
- bdrv_drain_recurse(bs, false);
46
+ bdrv_drain_recurse(bs);
47
aio_enable_external(bdrv_get_aio_context(bs));
48
}
49
50
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
51
aio_context_acquire(aio_context);
52
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
53
if (aio_context == bdrv_get_aio_context(bs)) {
54
- waited |= bdrv_drain_recurse(bs, true);
55
+ waited |= bdrv_drain_recurse(bs);
56
}
57
}
58
aio_context_release(aio_context);
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
60
aio_enable_external(aio_context);
61
bdrv_parent_drained_end(bs);
62
bdrv_drain_invoke(bs, false);
63
- bdrv_drain_recurse(bs, false);
64
+ bdrv_drain_recurse(bs);
65
aio_context_release(aio_context);
66
}
67
68
--
69
2.13.6
70
71
diff view generated by jsdifflib
New patch
1
The device is drained, so there is no point in waiting for requests at
2
the end of the drained section. Remove the bdrv_drain_recurse() calls
3
there.
1
4
5
The bdrv_drain_recurse() calls were introduced in commit 481cad48e5e
6
in order to call the .bdrv_co_drain_end() driver callback. This is now
7
done by a separate bdrv_drain_invoke() call.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
block/io.c | 2 --
14
1 file changed, 2 deletions(-)
15
16
diff --git a/block/io.c b/block/io.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/io.c
19
+++ b/block/io.c
20
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
21
22
bdrv_parent_drained_end(bs);
23
bdrv_drain_invoke(bs, false);
24
- bdrv_drain_recurse(bs);
25
aio_enable_external(bdrv_get_aio_context(bs));
26
}
27
28
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
29
aio_enable_external(aio_context);
30
bdrv_parent_drained_end(bs);
31
bdrv_drain_invoke(bs, false);
32
- bdrv_drain_recurse(bs);
33
aio_context_release(aio_context);
34
}
35
36
--
37
2.13.6
38
39
diff view generated by jsdifflib
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: Alberto Garcia <berto@igalia.com>
1
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
2
2
3
The size of the qcow2 L2 cache defaults to 32 MB, which can be easily
3
Since bdrv_co_preadv does all neccessary checks including
4
larger than the maximum amount of L2 metadata that the image can have.
4
reading after the end of the backing file, avoid duplication
5
For example: with 64 KB clusters the user would need a qcow2 image
5
of verification before bdrv_co_preadv call.
6
with a virtual size of 256 GB in order to have 32 MB of L2 metadata.
7
6
8
Because of that, since commit b749562d9822d14ef69c9eaa5f85903010b86c30
7
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
9
we forbid the L2 cache to become larger than the maximum amount of L2
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
metadata for the image, calculated using this formula:
9
Reviewed-by: Eric Blake <eblake@redhat.com>
11
12
uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);
13
14
The problem with this formula is that the result should be rounded up
15
to the cluster size because an L2 table on disk always takes one full
16
cluster.
17
18
For example, a 1280 MB qcow2 image with 64 KB clusters needs exactly
19
160 KB of L2 metadata, but we need 192 KB on disk (3 clusters) even if
20
the last 32 KB of those are not going to be used.
21
22
However QEMU rounds the numbers down and only creates 2 cache tables
23
(128 KB), which is not enough for the image.
24
25
A quick test doing 4KB random writes on a 1280 MB image gives me
26
around 500 IOPS, while with the correct cache size I get 16K IOPS.
27
28
Cc: qemu-stable@nongnu.org
29
Signed-off-by: Alberto Garcia <berto@igalia.com>
30
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
---
11
---
32
block/qcow2.c | 6 +++++-
12
block/qcow2.h | 3 ---
33
1 file changed, 5 insertions(+), 1 deletion(-)
13
block/qcow2.c | 51 ++++++++-------------------------------------------
14
2 files changed, 8 insertions(+), 46 deletions(-)
34
15
16
diff --git a/block/qcow2.h b/block/qcow2.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.h
19
+++ b/block/qcow2.h
20
@@ -XXX,XX +XXX,XX @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
21
}
22
23
/* qcow2.c functions */
24
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
25
- int64_t sector_num, int nb_sectors);
26
-
27
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
28
int refcount_order, bool generous_increase,
29
uint64_t *refblock_count);
35
diff --git a/block/qcow2.c b/block/qcow2.c
30
diff --git a/block/qcow2.c b/block/qcow2.c
36
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
37
--- a/block/qcow2.c
32
--- a/block/qcow2.c
38
+++ b/block/qcow2.c
33
+++ b/block/qcow2.c
39
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
34
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
40
bool l2_cache_entry_size_set;
35
return status;
41
int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
36
}
42
uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
37
43
- uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);
38
-/* handle reading after the end of the backing file */
44
+ uint64_t max_l2_entries = DIV_ROUND_UP(virtual_disk_size, s->cluster_size);
39
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
45
+ /* An L2 table is always one cluster in size so the max cache size
40
- int64_t offset, int bytes)
46
+ * should be a multiple of the cluster size. */
41
-{
47
+ uint64_t max_l2_cache = ROUND_UP(max_l2_entries * sizeof(uint64_t),
42
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
48
+ s->cluster_size);
43
- int n1;
49
44
-
50
combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE);
45
- if ((offset + bytes) <= bs_size) {
51
l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_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 */
52
--
104
--
53
2.20.1
105
2.13.6
54
106
55
107
diff view generated by jsdifflib
New patch
1
Removing a quorum child node with x-blockdev-change results in a quorum
2
driver state that cannot be recreated with create options because it
3
would require a list with gaps. This causes trouble in at least
4
.bdrv_refresh_filename().
1
5
6
Document this problem so that we won't accidentally mark the command
7
stable without having addressed it.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
---
12
qapi/block-core.json | 4 ++++
13
1 file changed, 4 insertions(+)
14
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
18
+++ b/qapi/block-core.json
19
@@ -XXX,XX +XXX,XX @@
20
# does not support all kinds of operations, all kinds of children, nor
21
# all block drivers.
22
#
23
+# FIXME Removing children from a quorum node means introducing gaps in the
24
+# child indices. This cannot be represented in the 'children' list of
25
+# BlockdevOptionsQuorum, as returned by .bdrv_refresh_filename().
26
+#
27
# Warning: The data in a new quorum child MUST be consistent with that of
28
# the rest of the array.
29
#
30
--
31
2.13.6
32
33
diff view generated by jsdifflib
New patch
1
From: Doug Gale <doug16k@gmail.com>
1
2
3
Add trace output for commands, errors, and undefined behavior.
4
Add guest error log output for undefined behavior.
5
Report invalid undefined accesses to MMIO.
6
Annotate unlikely error checks with unlikely.
7
8
Signed-off-by: Doug Gale <doug16k@gmail.com>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
hw/block/nvme.c | 349 ++++++++++++++++++++++++++++++++++++++++++--------
14
hw/block/trace-events | 93 ++++++++++++++
15
2 files changed, 390 insertions(+), 52 deletions(-)
16
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/block/nvme.c
20
+++ b/hw/block/nvme.c
21
@@ -XXX,XX +XXX,XX @@
22
#include "qapi/visitor.h"
23
#include "sysemu/block-backend.h"
24
25
+#include "qemu/log.h"
26
+#include "trace.h"
27
#include "nvme.h"
28
29
+#define NVME_GUEST_ERR(trace, fmt, ...) \
30
+ do { \
31
+ (trace_##trace)(__VA_ARGS__); \
32
+ qemu_log_mask(LOG_GUEST_ERROR, #trace \
33
+ " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
34
+ } while (0)
35
+
36
static void nvme_process_sq(void *opaque);
37
38
static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
39
@@ -XXX,XX +XXX,XX @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
40
{
41
if (cq->irq_enabled) {
42
if (msix_enabled(&(n->parent_obj))) {
43
+ trace_nvme_irq_msix(cq->vector);
44
msix_notify(&(n->parent_obj), cq->vector);
45
} else {
46
+ trace_nvme_irq_pin();
47
pci_irq_pulse(&n->parent_obj);
48
}
49
+ } else {
50
+ trace_nvme_irq_masked();
51
}
52
}
53
54
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
55
trans_len = MIN(len, trans_len);
56
int num_prps = (len >> n->page_bits) + 1;
57
58
- if (!prp1) {
59
+ if (unlikely(!prp1)) {
60
+ trace_nvme_err_invalid_prp();
61
return NVME_INVALID_FIELD | NVME_DNR;
62
} else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
63
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
64
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
65
}
66
len -= trans_len;
67
if (len) {
68
- if (!prp2) {
69
+ if (unlikely(!prp2)) {
70
+ trace_nvme_err_invalid_prp2_missing();
71
goto unmap;
72
}
73
if (len > n->page_size) {
74
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
75
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
76
77
if (i == n->max_prp_ents - 1 && len > n->page_size) {
78
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
79
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
80
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
81
goto unmap;
82
}
83
84
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
85
prp_ent = le64_to_cpu(prp_list[i]);
86
}
87
88
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
89
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
90
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
91
goto unmap;
92
}
93
94
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
95
i++;
96
}
97
} else {
98
- if (prp2 & (n->page_size - 1)) {
99
+ if (unlikely(prp2 & (n->page_size - 1))) {
100
+ trace_nvme_err_invalid_prp2_align(prp2);
101
goto unmap;
102
}
103
if (qsg->nsg) {
104
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
105
QEMUIOVector iov;
106
uint16_t status = NVME_SUCCESS;
107
108
+ trace_nvme_dma_read(prp1, prp2);
109
+
110
if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
111
return NVME_INVALID_FIELD | NVME_DNR;
112
}
113
if (qsg.nsg > 0) {
114
- if (dma_buf_read(ptr, len, &qsg)) {
115
+ if (unlikely(dma_buf_read(ptr, len, &qsg))) {
116
+ trace_nvme_err_invalid_dma();
117
status = NVME_INVALID_FIELD | NVME_DNR;
118
}
119
qemu_sglist_destroy(&qsg);
120
} else {
121
- if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
122
+ if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
123
+ trace_nvme_err_invalid_dma();
124
status = NVME_INVALID_FIELD | NVME_DNR;
125
}
126
qemu_iovec_destroy(&iov);
127
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
128
uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
129
uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
130
131
- if (slba + nlb > ns->id_ns.nsze) {
132
+ if (unlikely(slba + nlb > ns->id_ns.nsze)) {
133
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
134
return NVME_LBA_RANGE | NVME_DNR;
135
}
136
137
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
138
int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
139
enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;
140
141
- if ((slba + nlb) > ns->id_ns.nsze) {
142
+ trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba);
143
+
144
+ if (unlikely((slba + nlb) > ns->id_ns.nsze)) {
145
block_acct_invalid(blk_get_stats(n->conf.blk), acct);
146
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
147
return NVME_LBA_RANGE | NVME_DNR;
148
}
149
150
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
151
NvmeNamespace *ns;
152
uint32_t nsid = le32_to_cpu(cmd->nsid);
153
154
- if (nsid == 0 || nsid > n->num_namespaces) {
155
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
156
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
157
return NVME_INVALID_NSID | NVME_DNR;
158
}
159
160
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
161
case NVME_CMD_READ:
162
return nvme_rw(n, ns, cmd, req);
163
default:
164
+ trace_nvme_err_invalid_opc(cmd->opcode);
165
return NVME_INVALID_OPCODE | NVME_DNR;
166
}
167
}
168
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
169
NvmeCQueue *cq;
170
uint16_t qid = le16_to_cpu(c->qid);
171
172
- if (!qid || nvme_check_sqid(n, qid)) {
173
+ if (unlikely(!qid || nvme_check_sqid(n, qid))) {
174
+ trace_nvme_err_invalid_del_sq(qid);
175
return NVME_INVALID_QID | NVME_DNR;
176
}
177
178
+ trace_nvme_del_sq(qid);
179
+
180
sq = n->sq[qid];
181
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
182
req = QTAILQ_FIRST(&sq->out_req_list);
183
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
184
uint16_t qflags = le16_to_cpu(c->sq_flags);
185
uint64_t prp1 = le64_to_cpu(c->prp1);
186
187
- if (!cqid || nvme_check_cqid(n, cqid)) {
188
+ trace_nvme_create_sq(prp1, sqid, cqid, qsize, qflags);
189
+
190
+ if (unlikely(!cqid || nvme_check_cqid(n, cqid))) {
191
+ trace_nvme_err_invalid_create_sq_cqid(cqid);
192
return NVME_INVALID_CQID | NVME_DNR;
193
}
194
- if (!sqid || !nvme_check_sqid(n, sqid)) {
195
+ if (unlikely(!sqid || !nvme_check_sqid(n, sqid))) {
196
+ trace_nvme_err_invalid_create_sq_sqid(sqid);
197
return NVME_INVALID_QID | NVME_DNR;
198
}
199
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
200
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
201
+ trace_nvme_err_invalid_create_sq_size(qsize);
202
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
203
}
204
- if (!prp1 || prp1 & (n->page_size - 1)) {
205
+ if (unlikely(!prp1 || prp1 & (n->page_size - 1))) {
206
+ trace_nvme_err_invalid_create_sq_addr(prp1);
207
return NVME_INVALID_FIELD | NVME_DNR;
208
}
209
- if (!(NVME_SQ_FLAGS_PC(qflags))) {
210
+ if (unlikely(!(NVME_SQ_FLAGS_PC(qflags)))) {
211
+ trace_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags));
212
return NVME_INVALID_FIELD | NVME_DNR;
213
}
214
sq = g_malloc0(sizeof(*sq));
215
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd)
216
NvmeCQueue *cq;
217
uint16_t qid = le16_to_cpu(c->qid);
218
219
- if (!qid || nvme_check_cqid(n, qid)) {
220
+ if (unlikely(!qid || nvme_check_cqid(n, qid))) {
221
+ trace_nvme_err_invalid_del_cq_cqid(qid);
222
return NVME_INVALID_CQID | NVME_DNR;
223
}
224
225
cq = n->cq[qid];
226
- if (!QTAILQ_EMPTY(&cq->sq_list)) {
227
+ if (unlikely(!QTAILQ_EMPTY(&cq->sq_list))) {
228
+ trace_nvme_err_invalid_del_cq_notempty(qid);
229
return NVME_INVALID_QUEUE_DEL;
230
}
231
+ trace_nvme_del_cq(qid);
232
nvme_free_cq(cq, n);
233
return NVME_SUCCESS;
234
}
235
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
236
uint16_t qflags = le16_to_cpu(c->cq_flags);
237
uint64_t prp1 = le64_to_cpu(c->prp1);
238
239
- if (!cqid || !nvme_check_cqid(n, cqid)) {
240
+ trace_nvme_create_cq(prp1, cqid, vector, qsize, qflags,
241
+ NVME_CQ_FLAGS_IEN(qflags) != 0);
242
+
243
+ if (unlikely(!cqid || !nvme_check_cqid(n, cqid))) {
244
+ trace_nvme_err_invalid_create_cq_cqid(cqid);
245
return NVME_INVALID_CQID | NVME_DNR;
246
}
247
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
248
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
249
+ trace_nvme_err_invalid_create_cq_size(qsize);
250
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
251
}
252
- if (!prp1) {
253
+ if (unlikely(!prp1)) {
254
+ trace_nvme_err_invalid_create_cq_addr(prp1);
255
return NVME_INVALID_FIELD | NVME_DNR;
256
}
257
- if (vector > n->num_queues) {
258
+ if (unlikely(vector > n->num_queues)) {
259
+ trace_nvme_err_invalid_create_cq_vector(vector);
260
return NVME_INVALID_IRQ_VECTOR | NVME_DNR;
261
}
262
- if (!(NVME_CQ_FLAGS_PC(qflags))) {
263
+ if (unlikely(!(NVME_CQ_FLAGS_PC(qflags)))) {
264
+ trace_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags));
265
return NVME_INVALID_FIELD | NVME_DNR;
266
}
267
268
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c)
269
uint64_t prp1 = le64_to_cpu(c->prp1);
270
uint64_t prp2 = le64_to_cpu(c->prp2);
271
272
+ trace_nvme_identify_ctrl();
273
+
274
return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl),
275
prp1, prp2);
276
}
277
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c)
278
uint64_t prp1 = le64_to_cpu(c->prp1);
279
uint64_t prp2 = le64_to_cpu(c->prp2);
280
281
- if (nsid == 0 || nsid > n->num_namespaces) {
282
+ trace_nvme_identify_ns(nsid);
283
+
284
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
285
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
286
return NVME_INVALID_NSID | NVME_DNR;
287
}
288
289
ns = &n->namespaces[nsid - 1];
290
+
291
return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns),
292
prp1, prp2);
293
}
294
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
295
uint16_t ret;
296
int i, j = 0;
297
298
+ trace_nvme_identify_nslist(min_nsid);
299
+
300
list = g_malloc0(data_len);
301
for (i = 0; i < n->num_namespaces; i++) {
302
if (i < min_nsid) {
303
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
304
case 0x02:
305
return nvme_identify_nslist(n, c);
306
default:
307
+ trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns));
308
return NVME_INVALID_FIELD | NVME_DNR;
309
}
310
}
311
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
312
switch (dw10) {
313
case NVME_VOLATILE_WRITE_CACHE:
314
result = blk_enable_write_cache(n->conf.blk);
315
+ trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
316
break;
317
case NVME_NUMBER_OF_QUEUES:
318
result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
319
+ trace_nvme_getfeat_numq(result);
320
break;
321
default:
322
+ trace_nvme_err_invalid_getfeat(dw10);
323
return NVME_INVALID_FIELD | NVME_DNR;
324
}
325
326
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
327
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
328
break;
329
case NVME_NUMBER_OF_QUEUES:
330
+ trace_nvme_setfeat_numq((dw11 & 0xFFFF) + 1,
331
+ ((dw11 >> 16) & 0xFFFF) + 1,
332
+ n->num_queues - 1, n->num_queues - 1);
333
req->cqe.result =
334
cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
335
break;
336
default:
337
+ trace_nvme_err_invalid_setfeat(dw10);
338
return NVME_INVALID_FIELD | NVME_DNR;
339
}
340
return NVME_SUCCESS;
341
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
342
case NVME_ADM_CMD_GET_FEATURES:
343
return nvme_get_feature(n, cmd, req);
344
default:
345
+ trace_nvme_err_invalid_admin_opc(cmd->opcode);
346
return NVME_INVALID_OPCODE | NVME_DNR;
347
}
348
}
349
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
350
uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12;
351
uint32_t page_size = 1 << page_bits;
352
353
- if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq ||
354
- n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) ||
355
- NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) ||
356
- NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) ||
357
- NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) ||
358
- NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) ||
359
- NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) ||
360
- NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) ||
361
- !NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) {
362
+ if (unlikely(n->cq[0])) {
363
+ trace_nvme_err_startfail_cq();
364
+ return -1;
365
+ }
366
+ if (unlikely(n->sq[0])) {
367
+ trace_nvme_err_startfail_sq();
368
+ return -1;
369
+ }
370
+ if (unlikely(!n->bar.asq)) {
371
+ trace_nvme_err_startfail_nbarasq();
372
+ return -1;
373
+ }
374
+ if (unlikely(!n->bar.acq)) {
375
+ trace_nvme_err_startfail_nbaracq();
376
+ return -1;
377
+ }
378
+ if (unlikely(n->bar.asq & (page_size - 1))) {
379
+ trace_nvme_err_startfail_asq_misaligned(n->bar.asq);
380
+ return -1;
381
+ }
382
+ if (unlikely(n->bar.acq & (page_size - 1))) {
383
+ trace_nvme_err_startfail_acq_misaligned(n->bar.acq);
384
+ return -1;
385
+ }
386
+ if (unlikely(NVME_CC_MPS(n->bar.cc) <
387
+ NVME_CAP_MPSMIN(n->bar.cap))) {
388
+ trace_nvme_err_startfail_page_too_small(
389
+ NVME_CC_MPS(n->bar.cc),
390
+ NVME_CAP_MPSMIN(n->bar.cap));
391
+ return -1;
392
+ }
393
+ if (unlikely(NVME_CC_MPS(n->bar.cc) >
394
+ NVME_CAP_MPSMAX(n->bar.cap))) {
395
+ trace_nvme_err_startfail_page_too_large(
396
+ NVME_CC_MPS(n->bar.cc),
397
+ NVME_CAP_MPSMAX(n->bar.cap));
398
+ return -1;
399
+ }
400
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) <
401
+ NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) {
402
+ trace_nvme_err_startfail_cqent_too_small(
403
+ NVME_CC_IOCQES(n->bar.cc),
404
+ NVME_CTRL_CQES_MIN(n->bar.cap));
405
+ return -1;
406
+ }
407
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) >
408
+ NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) {
409
+ trace_nvme_err_startfail_cqent_too_large(
410
+ NVME_CC_IOCQES(n->bar.cc),
411
+ NVME_CTRL_CQES_MAX(n->bar.cap));
412
+ return -1;
413
+ }
414
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) <
415
+ NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) {
416
+ trace_nvme_err_startfail_sqent_too_small(
417
+ NVME_CC_IOSQES(n->bar.cc),
418
+ NVME_CTRL_SQES_MIN(n->bar.cap));
419
+ return -1;
420
+ }
421
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) >
422
+ NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) {
423
+ trace_nvme_err_startfail_sqent_too_large(
424
+ NVME_CC_IOSQES(n->bar.cc),
425
+ NVME_CTRL_SQES_MAX(n->bar.cap));
426
+ return -1;
427
+ }
428
+ if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) {
429
+ trace_nvme_err_startfail_asqent_sz_zero();
430
+ return -1;
431
+ }
432
+ if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) {
433
+ trace_nvme_err_startfail_acqent_sz_zero();
434
return -1;
435
}
436
437
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
438
static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
439
unsigned size)
440
{
441
+ if (unlikely(offset & (sizeof(uint32_t) - 1))) {
442
+ NVME_GUEST_ERR(nvme_ub_mmiowr_misaligned32,
443
+ "MMIO write not 32-bit aligned,"
444
+ " offset=0x%"PRIx64"", offset);
445
+ /* should be ignored, fall through for now */
446
+ }
447
+
448
+ if (unlikely(size < sizeof(uint32_t))) {
449
+ NVME_GUEST_ERR(nvme_ub_mmiowr_toosmall,
450
+ "MMIO write smaller than 32-bits,"
451
+ " offset=0x%"PRIx64", size=%u",
452
+ offset, size);
453
+ /* should be ignored, fall through for now */
454
+ }
455
+
456
switch (offset) {
457
- case 0xc:
458
+ case 0xc: /* INTMS */
459
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
460
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
461
+ "undefined access to interrupt mask set"
462
+ " when MSI-X is enabled");
463
+ /* should be ignored, fall through for now */
464
+ }
465
n->bar.intms |= data & 0xffffffff;
466
n->bar.intmc = n->bar.intms;
467
+ trace_nvme_mmio_intm_set(data & 0xffffffff,
468
+ n->bar.intmc);
469
break;
470
- case 0x10:
471
+ case 0x10: /* INTMC */
472
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
473
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
474
+ "undefined access to interrupt mask clr"
475
+ " when MSI-X is enabled");
476
+ /* should be ignored, fall through for now */
477
+ }
478
n->bar.intms &= ~(data & 0xffffffff);
479
n->bar.intmc = n->bar.intms;
480
+ trace_nvme_mmio_intm_clr(data & 0xffffffff,
481
+ n->bar.intmc);
482
break;
483
- case 0x14:
484
+ case 0x14: /* CC */
485
+ trace_nvme_mmio_cfg(data & 0xffffffff);
486
/* Windows first sends data, then sends enable bit */
487
if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) &&
488
!NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc))
489
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
490
491
if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) {
492
n->bar.cc = data;
493
- if (nvme_start_ctrl(n)) {
494
+ if (unlikely(nvme_start_ctrl(n))) {
495
+ trace_nvme_err_startfail();
496
n->bar.csts = NVME_CSTS_FAILED;
497
} else {
498
+ trace_nvme_mmio_start_success();
499
n->bar.csts = NVME_CSTS_READY;
500
}
501
} else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) {
502
+ trace_nvme_mmio_stopped();
503
nvme_clear_ctrl(n);
504
n->bar.csts &= ~NVME_CSTS_READY;
505
}
506
if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) {
507
- nvme_clear_ctrl(n);
508
- n->bar.cc = data;
509
- n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
510
+ trace_nvme_mmio_shutdown_set();
511
+ nvme_clear_ctrl(n);
512
+ n->bar.cc = data;
513
+ n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
514
} else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) {
515
- n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
516
- n->bar.cc = data;
517
+ trace_nvme_mmio_shutdown_cleared();
518
+ n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
519
+ n->bar.cc = data;
520
+ }
521
+ break;
522
+ case 0x1C: /* CSTS */
523
+ if (data & (1 << 4)) {
524
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ssreset_w1c_unsupported,
525
+ "attempted to W1C CSTS.NSSRO"
526
+ " but CAP.NSSRS is zero (not supported)");
527
+ } else if (data != 0) {
528
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ro_csts,
529
+ "attempted to set a read only bit"
530
+ " of controller status");
531
+ }
532
+ break;
533
+ case 0x20: /* NSSR */
534
+ if (data == 0x4E564D65) {
535
+ trace_nvme_ub_mmiowr_ssreset_unsupported();
536
+ } else {
537
+ /* The spec says that writes of other values have no effect */
538
+ return;
539
}
540
break;
541
- case 0x24:
542
+ case 0x24: /* AQA */
543
n->bar.aqa = data & 0xffffffff;
544
+ trace_nvme_mmio_aqattr(data & 0xffffffff);
545
break;
546
- case 0x28:
547
+ case 0x28: /* ASQ */
548
n->bar.asq = data;
549
+ trace_nvme_mmio_asqaddr(data);
550
break;
551
- case 0x2c:
552
+ case 0x2c: /* ASQ hi */
553
n->bar.asq |= data << 32;
554
+ trace_nvme_mmio_asqaddr_hi(data, n->bar.asq);
555
break;
556
- case 0x30:
557
+ case 0x30: /* ACQ */
558
+ trace_nvme_mmio_acqaddr(data);
559
n->bar.acq = data;
560
break;
561
- case 0x34:
562
+ case 0x34: /* ACQ hi */
563
n->bar.acq |= data << 32;
564
+ trace_nvme_mmio_acqaddr_hi(data, n->bar.acq);
565
break;
566
+ case 0x38: /* CMBLOC */
567
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbloc_reserved,
568
+ "invalid write to reserved CMBLOC"
569
+ " when CMBSZ is zero, ignored");
570
+ return;
571
+ case 0x3C: /* CMBSZ */
572
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
573
+ "invalid write to read only CMBSZ, ignored");
574
+ return;
575
default:
576
+ NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
577
+ "invalid MMIO write,"
578
+ " offset=0x%"PRIx64", data=%"PRIx64"",
579
+ offset, data);
580
break;
581
}
582
}
583
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
584
uint8_t *ptr = (uint8_t *)&n->bar;
585
uint64_t val = 0;
586
587
+ if (unlikely(addr & (sizeof(uint32_t) - 1))) {
588
+ NVME_GUEST_ERR(nvme_ub_mmiord_misaligned32,
589
+ "MMIO read not 32-bit aligned,"
590
+ " offset=0x%"PRIx64"", addr);
591
+ /* should RAZ, fall through for now */
592
+ } else if (unlikely(size < sizeof(uint32_t))) {
593
+ NVME_GUEST_ERR(nvme_ub_mmiord_toosmall,
594
+ "MMIO read smaller than 32-bits,"
595
+ " offset=0x%"PRIx64"", addr);
596
+ /* should RAZ, fall through for now */
597
+ }
598
+
599
if (addr < sizeof(n->bar)) {
600
memcpy(&val, ptr + addr, size);
601
+ } else {
602
+ NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
603
+ "MMIO read beyond last register,"
604
+ " offset=0x%"PRIx64", returning 0", addr);
605
}
606
+
607
return val;
608
}
609
610
@@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
611
{
612
uint32_t qid;
613
614
- if (addr & ((1 << 2) - 1)) {
615
+ if (unlikely(addr & ((1 << 2) - 1))) {
616
+ NVME_GUEST_ERR(nvme_ub_db_wr_misaligned,
617
+ "doorbell write not 32-bit aligned,"
618
+ " offset=0x%"PRIx64", ignoring", addr);
619
return;
620
}
621
622
if (((addr - 0x1000) >> 2) & 1) {
623
+ /* Completion queue doorbell write */
624
+
625
uint16_t new_head = val & 0xffff;
626
int start_sqs;
627
NvmeCQueue *cq;
628
629
qid = (addr - (0x1000 + (1 << 2))) >> 3;
630
- if (nvme_check_cqid(n, qid)) {
631
+ if (unlikely(nvme_check_cqid(n, qid))) {
632
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq,
633
+ "completion queue doorbell write"
634
+ " for nonexistent queue,"
635
+ " sqid=%"PRIu32", ignoring", qid);
636
return;
637
}
638
639
cq = n->cq[qid];
640
- if (new_head >= cq->size) {
641
+ if (unlikely(new_head >= cq->size)) {
642
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cqhead,
643
+ "completion queue doorbell write value"
644
+ " beyond queue size, sqid=%"PRIu32","
645
+ " new_head=%"PRIu16", ignoring",
646
+ qid, new_head);
647
return;
648
}
649
650
@@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
651
nvme_isr_notify(n, cq);
652
}
653
} else {
654
+ /* Submission queue doorbell write */
655
+
656
uint16_t new_tail = val & 0xffff;
657
NvmeSQueue *sq;
658
659
qid = (addr - 0x1000) >> 3;
660
- if (nvme_check_sqid(n, qid)) {
661
+ if (unlikely(nvme_check_sqid(n, qid))) {
662
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sq,
663
+ "submission queue doorbell write"
664
+ " for nonexistent queue,"
665
+ " sqid=%"PRIu32", ignoring", qid);
666
return;
667
}
668
669
sq = n->sq[qid];
670
- if (new_tail >= sq->size) {
671
+ if (unlikely(new_tail >= sq->size)) {
672
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sqtail,
673
+ "submission queue doorbell write value"
674
+ " beyond queue size, sqid=%"PRIu32","
675
+ " new_tail=%"PRIu16", ignoring",
676
+ qid, new_tail);
677
return;
678
}
679
680
diff --git a/hw/block/trace-events b/hw/block/trace-events
681
index XXXXXXX..XXXXXXX 100644
682
--- a/hw/block/trace-events
683
+++ b/hw/block/trace-events
684
@@ -XXX,XX +XXX,XX @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6
685
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
686
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
687
688
+# hw/block/nvme.c
689
+# nvme traces for successful events
690
+nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
691
+nvme_irq_pin(void) "pulsing IRQ pin"
692
+nvme_irq_masked(void) "IRQ is masked"
693
+nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
694
+nvme_rw(char const *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
695
+nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
696
+nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
697
+nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
698
+nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16""
699
+nvme_identify_ctrl(void) "identify controller"
700
+nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
701
+nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
702
+nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s"
703
+nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
704
+nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
705
+nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
706
+nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
707
+nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
708
+nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
709
+nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
710
+nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
711
+nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
712
+nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
713
+nvme_mmio_start_success(void) "setting controller enable bit succeeded"
714
+nvme_mmio_stopped(void) "cleared controller enable bit"
715
+nvme_mmio_shutdown_set(void) "shutdown bit set"
716
+nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
717
+
718
+# nvme traces for error conditions
719
+nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
720
+nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
721
+nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
722
+nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
723
+nvme_err_invalid_field(void) "invalid field"
724
+nvme_err_invalid_prp(void) "invalid PRP"
725
+nvme_err_invalid_sgl(void) "invalid SGL"
726
+nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u"
727
+nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
728
+nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
729
+nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
730
+nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
731
+nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
732
+nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
733
+nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
734
+nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
735
+nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
736
+nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
737
+nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
738
+nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
739
+nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
740
+nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
741
+nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
742
+nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
743
+nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
744
+nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
745
+nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
746
+nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
747
+nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
748
+nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
749
+nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null"
750
+nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64""
751
+nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64""
752
+nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u"
753
+nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u"
754
+nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u"
755
+nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u"
756
+nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u"
757
+nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u"
758
+nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
759
+nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
760
+nvme_err_startfail(void) "setting controller enable bit failed"
761
+
762
+# Traces for undefined behavior
763
+nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64""
764
+nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u"
765
+nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled"
766
+nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status"
767
+nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)"
768
+nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
769
+nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
770
+nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
771
+nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
772
+nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
773
+nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
774
+nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0"
775
+nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring"
776
+nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring"
777
+nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring"
778
+nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring"
779
+nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring"
780
+
781
# hw/block/xen_disk.c
782
xen_disk_alloc(char *name) "%s"
783
xen_disk_init(char *name) "%s"
784
--
785
2.13.6
786
787
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
The 'blockdev-create' QMP command was introduced as experimental
3
Management tools create overlays of running guests with qemu-img:
4
feature in commit b0292b851b8, using the assert() debug call.
5
It got promoted to 'stable' command in 3fb588a0f2c, but the
6
assert call was not removed.
7
4
8
Some block drivers are optional, and bdrv_find_format() might
5
$ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2
9
return a NULL value, triggering the assertion.
10
6
11
Stable code is not expected to abort, so return an error instead.
7
but this doesn't work anymore due to image locking:
12
8
13
This is easily reproducible when libnfs is not installed:
9
qemu-img: /overlay/image.qcow2: Failed to get shared "write" lock
14
10
Is another process using the image?
15
./configure
11
Could not open backing image to determine size.
16
[...]
12
Use the force share option to allow this use case again.
17
module support no
18
Block whitelist (rw)
19
Block whitelist (ro)
20
libiscsi support yes
21
libnfs support no
22
[...]
23
24
Start QEMU:
25
26
$ qemu-system-x86_64 -S -qmp unix:/tmp/qemu.qmp,server,nowait
27
28
Send the 'blockdev-create' with the 'nfs' driver:
29
30
$ ( cat << 'EOF'
31
{'execute': 'qmp_capabilities'}
32
{'execute': 'blockdev-create', 'arguments': {'job-id': 'x', 'options': {'size': 0, 'driver': 'nfs', 'location': {'path': '/', 'server': {'host': '::1', 'type': 'inet'}}}}, 'id': 'x'}
33
EOF
34
) | socat STDIO UNIX:/tmp/qemu.qmp
35
{"QMP": {"version": {"qemu": {"micro": 50, "minor": 1, "major": 4}, "package": "v4.1.0-733-g89ea03a7dc"}, "capabilities": ["oob"]}}
36
{"return": {}}
37
38
QEMU crashes:
39
40
$ gdb qemu-system-x86_64 core
41
Program received signal SIGSEGV, Segmentation fault.
42
(gdb) bt
43
#0 0x00007ffff510957f in raise () at /lib64/libc.so.6
44
#1 0x00007ffff50f3895 in abort () at /lib64/libc.so.6
45
#2 0x00007ffff50f3769 in _nl_load_domain.cold.0 () at /lib64/libc.so.6
46
#3 0x00007ffff5101a26 in .annobin_assert.c_end () at /lib64/libc.so.6
47
#4 0x0000555555d7e1f1 in qmp_blockdev_create (job_id=0x555556baee40 "x", options=0x555557666610, errp=0x7fffffffc770) at block/create.c:69
48
#5 0x0000555555c96b52 in qmp_marshal_blockdev_create (args=0x7fffdc003830, ret=0x7fffffffc7f8, errp=0x7fffffffc7f0) at qapi/qapi-commands-block-core.c:1314
49
#6 0x0000555555deb0a0 in do_qmp_dispatch (cmds=0x55555645de70 <qmp_commands>, request=0x7fffdc005c70, allow_oob=false, errp=0x7fffffffc898) at qapi/qmp-dispatch.c:131
50
#7 0x0000555555deb2a1 in qmp_dispatch (cmds=0x55555645de70 <qmp_commands>, request=0x7fffdc005c70, allow_oob=false) at qapi/qmp-dispatch.c:174
51
52
With this patch applied, QEMU returns a QMP error:
53
54
{'execute': 'blockdev-create', 'arguments': {'job-id': 'x', 'options': {'size': 0, 'driver': 'nfs', 'location': {'path': '/', 'server': {'host': '::1', 'type': 'inet'}}}}, 'id': 'x'}
55
{"id": "x", "error": {"class": "GenericError", "desc": "Block driver 'nfs' not found or not supported"}}
56
13
57
Cc: qemu-stable@nongnu.org
14
Cc: qemu-stable@nongnu.org
58
Reported-by: Xu Tian <xutian@redhat.com>
15
Signed-off-by: Fam Zheng <famz@redhat.com>
59
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
60
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
61
Reviewed-by: John Snow <jsnow@redhat.com>
62
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
63
---
18
---
64
block/create.c | 6 +++++-
19
block.c | 3 ++-
65
1 file changed, 5 insertions(+), 1 deletion(-)
20
1 file changed, 2 insertions(+), 1 deletion(-)
66
21
67
diff --git a/block/create.c b/block/create.c
22
diff --git a/block.c b/block.c
68
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
69
--- a/block/create.c
24
--- a/block.c
70
+++ b/block/create.c
25
+++ b/block.c
71
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
26
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
72
const char *fmt = BlockdevDriver_str(options->driver);
27
back_flags = flags;
73
BlockDriver *drv = bdrv_find_format(fmt);
28
back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
74
29
75
+ if (!drv) {
30
+ backing_options = qdict_new();
76
+ error_setg(errp, "Block driver '%s' not found or not supported", fmt);
31
if (backing_fmt) {
77
+ return;
32
- backing_options = qdict_new();
78
+ }
33
qdict_put_str(backing_options, "driver", backing_fmt);
79
+
34
}
80
/* If the driver is in the schema, we know that it exists. But it may not
35
+ qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true);
81
* be whitelisted. */
36
82
- assert(drv);
37
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
83
if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
38
&local_err);
84
error_setg(errp, "Driver is not whitelisted");
85
return;
86
--
39
--
87
2.20.1
40
2.13.6
88
41
89
42
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
handle_alloc() tries to find as many contiguous clusters that need
3
It's not working anymore since QEMU v1.3.0 - time to remove it now.
4
copy-on-write as possible in order to allocate all of them at the same
5
time.
6
4
7
However, compressed clusters are only overwritten one by one, so let's
5
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
say that we have an image with 1024 consecutive compressed clusters:
6
Reviewed-by: John Snow <jsnow@redhat.com>
9
7
Reviewed-by: Markus Armbruster <armbru@redhat.com>
10
qemu-img create -f qcow2 hd.qcow2 64M
11
for f in `seq 0 64 65472`; do
12
qemu-io -c "write -c ${f}k 64k" hd.qcow2
13
done
14
15
In this case trying to overwrite the whole image with one large write
16
request results in 1024 separate allocations:
17
18
qemu-io -c "write 0 64M" hd.qcow2
19
20
This restriction comes from commit 095a9c58ce12afeeb90c2 from 2008.
21
Nowadays QEMU can overwrite multiple compressed clusters just fine,
22
and in fact it already does: as long as the first cluster that
23
handle_alloc() finds is not compressed, all other compressed clusters
24
in the same batch will be overwritten in one go:
25
26
qemu-img create -f qcow2 hd.qcow2 64M
27
qemu-io -c "write -z 0 64k" hd.qcow2
28
for f in `seq 64 64 65472`; do
29
qemu-io -c "write -c ${f}k 64k" hd.qcow2
30
done
31
32
Compared to the previous one, overwriting this image on my computer
33
goes from 8.35s down to 230ms.
34
35
Signed-off-by: Alberto Garcia <berto@igalia.com>
36
Reviewed-by: John Snow <jsnow@redhat.com
37
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
38
---
9
---
39
block/qcow2-cluster.c | 8 +-------
10
blockdev.c | 11 -----------
40
1 file changed, 1 insertion(+), 7 deletions(-)
11
qemu-doc.texi | 6 ------
12
2 files changed, 17 deletions(-)
41
13
42
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
14
diff --git a/blockdev.c b/blockdev.c
43
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
44
--- a/block/qcow2-cluster.c
16
--- a/blockdev.c
45
+++ b/block/qcow2-cluster.c
17
+++ b/blockdev.c
46
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
18
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
19
.type = QEMU_OPT_STRING,
20
.help = "chs translation (auto, lba, none)",
21
},{
22
- .name = "boot",
23
- .type = QEMU_OPT_BOOL,
24
- .help = "(deprecated, ignored)",
25
- },{
26
.name = "addr",
27
.type = QEMU_OPT_STRING,
28
.help = "pci address (virtio only)",
29
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
30
goto fail;
47
}
31
}
48
32
49
entry = be64_to_cpu(l2_slice[l2_index]);
33
- /* Deprecated option boot=[on|off] */
34
- if (qemu_opt_get(legacy_opts, "boot") != NULL) {
35
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
36
- "ignored. Future versions will reject this parameter. Please "
37
- "update your scripts.\n");
38
- }
50
-
39
-
51
- /* For the moment, overwrite compressed clusters one by one */
40
/* Other deprecated options */
52
- if (entry & QCOW_OFLAG_COMPRESSED) {
41
if (!qtest_enabled()) {
53
- nb_clusters = 1;
42
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
54
- } else {
43
diff --git a/qemu-doc.texi b/qemu-doc.texi
55
- nb_clusters = count_cow_clusters(bs, nb_clusters, l2_slice, l2_index);
44
index XXXXXXX..XXXXXXX 100644
56
- }
45
--- a/qemu-doc.texi
57
+ nb_clusters = count_cow_clusters(bs, nb_clusters, l2_slice, l2_index);
46
+++ b/qemu-doc.texi
58
47
@@ -XXX,XX +XXX,XX @@ deprecated.
59
/* This function is only called when there were no non-COW clusters, so if
48
60
* we can't find any unallocated or COW clusters either, something is
49
@section System emulator command line arguments
50
51
-@subsection -drive boot=on|off (since 1.3.0)
52
-
53
-The ``boot=on|off'' option to the ``-drive'' argument is
54
-ignored. Applications should use the ``bootindex=N'' parameter
55
-to set an absolute ordering between devices instead.
56
-
57
@subsection -tdf (since 1.3.0)
58
59
The ``-tdf'' argument is ignored. The behaviour implemented
61
--
60
--
62
2.20.1
61
2.13.6
63
62
64
63
diff view generated by jsdifflib
New patch
1
1
From: Thomas Huth <thuth@redhat.com>
2
3
It's been marked as deprecated since QEMU v2.10.0, and so far nobody
4
complained that we should keep it, so let's remove this legacy option
5
now to simplify the code quite a bit.
6
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
vl.c | 86 ++-------------------------------------------------------
13
qemu-doc.texi | 8 ------
14
qemu-options.hx | 19 ++-----------
15
3 files changed, 4 insertions(+), 109 deletions(-)
16
17
diff --git a/vl.c b/vl.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/vl.c
20
+++ b/vl.c
21
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
22
const char *boot_order = NULL;
23
const char *boot_once = NULL;
24
DisplayState *ds;
25
- int cyls, heads, secs, translation;
26
QemuOpts *opts, *machine_opts;
27
- QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL;
28
+ QemuOpts *icount_opts = NULL, *accel_opts = NULL;
29
QemuOptsList *olist;
30
int optind;
31
const char *optarg;
32
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
33
34
cpu_model = NULL;
35
snapshot = 0;
36
- cyls = heads = secs = 0;
37
- translation = BIOS_ATA_TRANSLATION_AUTO;
38
39
nb_nics = 0;
40
41
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
42
if (optind >= argc)
43
break;
44
if (argv[optind][0] != '-') {
45
- hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
46
+ drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
47
} else {
48
const QEMUOption *popt;
49
50
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
51
cpu_model = optarg;
52
break;
53
case QEMU_OPTION_hda:
54
- {
55
- char buf[256];
56
- if (cyls == 0)
57
- snprintf(buf, sizeof(buf), "%s", HD_OPTS);
58
- else
59
- snprintf(buf, sizeof(buf),
60
- "%s,cyls=%d,heads=%d,secs=%d%s",
61
- HD_OPTS , cyls, heads, secs,
62
- translation == BIOS_ATA_TRANSLATION_LBA ?
63
- ",trans=lba" :
64
- translation == BIOS_ATA_TRANSLATION_NONE ?
65
- ",trans=none" : "");
66
- drive_add(IF_DEFAULT, 0, optarg, buf);
67
- break;
68
- }
69
case QEMU_OPTION_hdb:
70
case QEMU_OPTION_hdc:
71
case QEMU_OPTION_hdd:
72
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
73
case QEMU_OPTION_snapshot:
74
snapshot = 1;
75
break;
76
- case QEMU_OPTION_hdachs:
77
- {
78
- const char *p;
79
- p = optarg;
80
- cyls = strtol(p, (char **)&p, 0);
81
- if (cyls < 1 || cyls > 16383)
82
- goto chs_fail;
83
- if (*p != ',')
84
- goto chs_fail;
85
- p++;
86
- heads = strtol(p, (char **)&p, 0);
87
- if (heads < 1 || heads > 16)
88
- goto chs_fail;
89
- if (*p != ',')
90
- goto chs_fail;
91
- p++;
92
- secs = strtol(p, (char **)&p, 0);
93
- if (secs < 1 || secs > 63)
94
- goto chs_fail;
95
- if (*p == ',') {
96
- p++;
97
- if (!strcmp(p, "large")) {
98
- translation = BIOS_ATA_TRANSLATION_LARGE;
99
- } else if (!strcmp(p, "rechs")) {
100
- translation = BIOS_ATA_TRANSLATION_RECHS;
101
- } else if (!strcmp(p, "none")) {
102
- translation = BIOS_ATA_TRANSLATION_NONE;
103
- } else if (!strcmp(p, "lba")) {
104
- translation = BIOS_ATA_TRANSLATION_LBA;
105
- } else if (!strcmp(p, "auto")) {
106
- translation = BIOS_ATA_TRANSLATION_AUTO;
107
- } else {
108
- goto chs_fail;
109
- }
110
- } else if (*p != '\0') {
111
- chs_fail:
112
- error_report("invalid physical CHS format");
113
- exit(1);
114
- }
115
- if (hda_opts != NULL) {
116
- qemu_opt_set_number(hda_opts, "cyls", cyls,
117
- &error_abort);
118
- qemu_opt_set_number(hda_opts, "heads", heads,
119
- &error_abort);
120
- qemu_opt_set_number(hda_opts, "secs", secs,
121
- &error_abort);
122
- if (translation == BIOS_ATA_TRANSLATION_LARGE) {
123
- qemu_opt_set(hda_opts, "trans", "large",
124
- &error_abort);
125
- } else if (translation == BIOS_ATA_TRANSLATION_RECHS) {
126
- qemu_opt_set(hda_opts, "trans", "rechs",
127
- &error_abort);
128
- } else if (translation == BIOS_ATA_TRANSLATION_LBA) {
129
- qemu_opt_set(hda_opts, "trans", "lba",
130
- &error_abort);
131
- } else if (translation == BIOS_ATA_TRANSLATION_NONE) {
132
- qemu_opt_set(hda_opts, "trans", "none",
133
- &error_abort);
134
- }
135
- }
136
- }
137
- error_report("'-hdachs' is deprecated, please use '-device"
138
- " ide-hd,cyls=c,heads=h,secs=s,...' instead");
139
- break;
140
case QEMU_OPTION_numa:
141
opts = qemu_opts_parse_noisily(qemu_find_opts("numa"),
142
optarg, true);
143
diff --git a/qemu-doc.texi b/qemu-doc.texi
144
index XXXXXXX..XXXXXXX 100644
145
--- a/qemu-doc.texi
146
+++ b/qemu-doc.texi
147
@@ -XXX,XX +XXX,XX @@ The ``--net dump'' argument is now replaced with the
148
``-object filter-dump'' argument which works in combination
149
with the modern ``-netdev`` backends instead.
150
151
-@subsection -hdachs (since 2.10.0)
152
-
153
-The ``-hdachs'' argument is now a synonym for setting
154
-the ``cyls'', ``heads'', ``secs'', and ``trans'' properties
155
-on the ``ide-hd'' device using the ``-device'' argument.
156
-The new syntax allows different settings to be provided
157
-per disk.
158
-
159
@subsection -usbdevice (since 2.10.0)
160
161
The ``-usbdevice DEV'' argument is now a synonym for setting
162
diff --git a/qemu-options.hx b/qemu-options.hx
163
index XXXXXXX..XXXXXXX 100644
164
--- a/qemu-options.hx
165
+++ b/qemu-options.hx
166
@@ -XXX,XX +XXX,XX @@ of available connectors of a given interface type.
167
@item media=@var{media}
168
This option defines the type of the media: disk or cdrom.
169
@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
170
-These options have the same definition as they have in @option{-hdachs}.
171
-These parameters are deprecated, use the corresponding parameters
172
+Force disk physical geometry and the optional BIOS translation (trans=none or
173
+lba). These parameters are deprecated, use the corresponding parameters
174
of @code{-device} instead.
175
@item snapshot=@var{snapshot}
176
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
177
@@ -XXX,XX +XXX,XX @@ the raw disk image you use is not written back. You can however force
178
the write back by pressing @key{C-a s} (@pxref{disk_images}).
179
ETEXI
180
181
-DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
182
- "-hdachs c,h,s[,t]\n" \
183
- " force hard disk 0 physical geometry and the optional BIOS\n" \
184
- " translation (t=none or lba) (usually QEMU can guess them)\n",
185
- QEMU_ARCH_ALL)
186
-STEXI
187
-@item -hdachs @var{c},@var{h},@var{s},[,@var{t}]
188
-@findex -hdachs
189
-Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
190
-@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
191
-translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
192
-all those parameters. This option is deprecated, please use
193
-@code{-device ide-hd,cyls=c,heads=h,secs=s,...} instead.
194
-ETEXI
195
-
196
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
197
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
198
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n"
199
--
200
2.13.6
201
202
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
As the iotests run longer under the Valgrind, the QEMU_COMM_TIMEOUT is
3
Looks like we forgot to announce the deprecation of these options in
4
to be increased in the test cases 028, 183 and 192 when running under
4
the corresponding chapter of the qemu-doc text, so let's do that now.
5
the Valgrind.
6
5
7
Suggested-by: Roman Kagan <rkagan@virtuozzo.com>
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
10
---
13
tests/qemu-iotests/028 | 6 +++++-
11
qemu-doc.texi | 15 +++++++++++++++
14
tests/qemu-iotests/183 | 9 ++++++++-
12
1 file changed, 15 insertions(+)
15
tests/qemu-iotests/192 | 6 +++++-
16
3 files changed, 18 insertions(+), 3 deletions(-)
17
13
18
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
14
diff --git a/qemu-doc.texi b/qemu-doc.texi
19
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/028
16
--- a/qemu-doc.texi
21
+++ b/tests/qemu-iotests/028
17
+++ b/qemu-doc.texi
22
@@ -XXX,XX +XXX,XX @@ echo
18
@@ -XXX,XX +XXX,XX @@ longer be directly supported in QEMU.
23
qemu_comm_method="monitor"
19
The ``-drive if=scsi'' argument is replaced by the the
24
_launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk
20
``-device BUS-TYPE'' argument combined with ``-drive if=none''.
25
h=$QEMU_HANDLE
21
26
-QEMU_COMM_TIMEOUT=1
22
+@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
27
+if [ "${VALGRIND_QEMU}" == "y" ]; then
23
+
28
+ QEMU_COMM_TIMEOUT=7
24
+The drive geometry arguments are replaced by the the geometry arguments
29
+else
25
+that can be specified with the ``-device'' parameter.
30
+ QEMU_COMM_TIMEOUT=1
26
+
31
+fi
27
+@subsection -drive serial=... (since 2.10.0)
32
28
+
33
# Silence output since it contains the disk image path and QEMU's readline
29
+The drive serial argument is replaced by the the serial argument
34
# character echoing makes it very hard to filter the output. Plus, there
30
+that can be specified with the ``-device'' parameter.
35
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
31
+
36
index XXXXXXX..XXXXXXX 100755
32
+@subsection -drive addr=... (since 2.10.0)
37
--- a/tests/qemu-iotests/183
33
+
38
+++ b/tests/qemu-iotests/183
34
+The drive addr argument is replaced by the the addr argument
39
@@ -XXX,XX +XXX,XX @@ if echo "$reply" | grep "compiled without old-style" > /dev/null; then
35
+that can be specified with the ``-device'' parameter.
40
_notrun "migrate -b support not compiled in"
36
+
41
fi
37
@subsection -net dump (since 2.10.0)
42
38
43
-QEMU_COMM_TIMEOUT=0.1 qemu_cmd_repeat=50 silent=yes \
39
The ``--net dump'' argument is now replaced with the
44
+timeout_comm=$QEMU_COMM_TIMEOUT
45
+if [ "${VALGRIND_QEMU}" == "y" ]; then
46
+ QEMU_COMM_TIMEOUT=4
47
+else
48
+ QEMU_COMM_TIMEOUT=0.1
49
+fi
50
+qemu_cmd_repeat=50 silent=yes \
51
_send_qemu_cmd $src "{ 'execute': 'query-migrate' }" '"status": "completed"'
52
+QEMU_COMM_TIMEOUT=$timeout_comm
53
_send_qemu_cmd $src "{ 'execute': 'query-status' }" "return"
54
55
echo
56
diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192
57
index XXXXXXX..XXXXXXX 100755
58
--- a/tests/qemu-iotests/192
59
+++ b/tests/qemu-iotests/192
60
@@ -XXX,XX +XXX,XX @@ fi
61
qemu_comm_method="monitor"
62
_launch_qemu -drive $DRIVE_ARG -incoming defer
63
h=$QEMU_HANDLE
64
-QEMU_COMM_TIMEOUT=1
65
+if [ "${VALGRIND_QEMU}" == "y" ]; then
66
+ QEMU_COMM_TIMEOUT=7
67
+else
68
+ QEMU_COMM_TIMEOUT=1
69
+fi
70
71
_send_qemu_cmd $h "nbd_server_start unix:$TEST_DIR/nbd" "(qemu)"
72
_send_qemu_cmd $h "nbd_server_add -w drive0" "(qemu)"
73
--
40
--
74
2.20.1
41
2.13.6
75
42
76
43
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
This patch removes xfs_write_zeroes() and xfs_discard(). Both functions
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
have been added just before the same feature was present through
5
fallocate():
6
7
- fallocate() has supported PUNCH_HOLE for XFS since Linux 2.6.38 (March
8
2011); xfs_discard() was added in December 2010.
9
10
- fallocate() has supported ZERO_RANGE for XFS since Linux 3.15 (June
11
2014); xfs_write_zeroes() was added in November 2013.
12
13
Nowadays, all systems that qemu runs on should support both fallocate()
14
features (RHEL 7's kernel does).
15
16
xfsctl() is still useful for getting the request alignment for O_DIRECT,
17
so this patch does not remove our dependency on it completely.
18
19
Note that xfs_write_zeroes() had a bug: It calls ftruncate() when the
20
file is shorter than the specified range (because ZERO_RANGE does not
21
increase the file length). ftruncate() may yield and then discard data
22
that parallel write requests have written past the EOF in the meantime.
23
Dropping the function altogether fixes the bug.
24
25
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
26
Fixes: 50ba5b2d994853b38fed10e0841b119da0f8b8e5
27
Reported-by: Lukáš Doktor <ldoktor@redhat.com>
28
Cc: qemu-stable@nongnu.org
29
Signed-off-by: Max Reitz <mreitz@redhat.com>
30
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
31
Reviewed-by: John Snow <jsnow@redhat.com>
32
Tested-by: Stefano Garzarella <sgarzare@redhat.com>
33
Tested-by: John Snow <jsnow@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
---
5
---
36
block/file-posix.c | 77 +---------------------------------------------
6
include/block/block_int.h | 1 -
37
1 file changed, 1 insertion(+), 76 deletions(-)
7
block/io.c | 18 ------------------
8
2 files changed, 19 deletions(-)
38
9
39
diff --git a/block/file-posix.c b/block/file-posix.c
10
diff --git a/include/block/block_int.h b/include/block/block_int.h
40
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
41
--- a/block/file-posix.c
12
--- a/include/block/block_int.h
42
+++ b/block/file-posix.c
13
+++ b/include/block/block_int.h
43
@@ -XXX,XX +XXX,XX @@ out:
14
@@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk);
44
}
15
bool blk_dev_is_medium_locked(BlockBackend *blk);
16
17
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
18
-bool bdrv_requests_pending(BlockDriverState *bs);
19
20
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
21
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
22
diff --git a/block/io.c b/block/io.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/io.c
25
+++ b/block/io.c
26
@@ -XXX,XX +XXX,XX @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
27
assert(old >= 1);
45
}
28
}
46
29
47
-#ifdef CONFIG_XFS
30
-/* Check if any requests are in-flight (including throttled requests) */
48
-static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
31
-bool bdrv_requests_pending(BlockDriverState *bs)
49
-{
32
-{
50
- int64_t len;
33
- BdrvChild *child;
51
- struct xfs_flock64 fl;
52
- int err;
53
-
34
-
54
- len = lseek(s->fd, 0, SEEK_END);
35
- if (atomic_read(&bs->in_flight)) {
55
- if (len < 0) {
36
- return true;
56
- return -errno;
57
- }
37
- }
58
-
38
-
59
- if (offset + bytes > len) {
39
- QLIST_FOREACH(child, &bs->children, next) {
60
- /* XFS_IOC_ZERO_RANGE does not increase the file length */
40
- if (bdrv_requests_pending(child->bs)) {
61
- if (ftruncate(s->fd, offset + bytes) < 0) {
41
- return true;
62
- return -errno;
63
- }
42
- }
64
- }
43
- }
65
-
44
-
66
- memset(&fl, 0, sizeof(fl));
45
- return false;
67
- fl.l_whence = SEEK_SET;
68
- fl.l_start = offset;
69
- fl.l_len = bytes;
70
-
71
- if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) {
72
- err = errno;
73
- trace_file_xfs_write_zeroes(strerror(errno));
74
- return -err;
75
- }
76
-
77
- return 0;
78
-}
46
-}
79
-
47
-
80
-static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
48
typedef struct {
81
-{
49
Coroutine *co;
82
- struct xfs_flock64 fl;
50
BlockDriverState *bs;
83
- int err;
84
-
85
- memset(&fl, 0, sizeof(fl));
86
- fl.l_whence = SEEK_SET;
87
- fl.l_start = offset;
88
- fl.l_len = bytes;
89
-
90
- if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
91
- err = errno;
92
- trace_file_xfs_discard(strerror(errno));
93
- return -err;
94
- }
95
-
96
- return 0;
97
-}
98
-#endif
99
-
100
static int translate_err(int err)
101
{
102
if (err == -ENODEV || err == -ENOSYS || err == -EOPNOTSUPP ||
103
@@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb)
104
static int handle_aiocb_write_zeroes(void *opaque)
105
{
106
RawPosixAIOData *aiocb = opaque;
107
-#if defined(CONFIG_FALLOCATE) || defined(CONFIG_XFS)
108
- BDRVRawState *s = aiocb->bs->opaque;
109
-#endif
110
#ifdef CONFIG_FALLOCATE
111
+ BDRVRawState *s = aiocb->bs->opaque;
112
int64_t len;
113
#endif
114
115
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_write_zeroes(void *opaque)
116
return handle_aiocb_write_zeroes_block(aiocb);
117
}
118
119
-#ifdef CONFIG_XFS
120
- if (s->is_xfs) {
121
- return xfs_write_zeroes(s, aiocb->aio_offset, aiocb->aio_nbytes);
122
- }
123
-#endif
124
-
125
#ifdef CONFIG_FALLOCATE_ZERO_RANGE
126
if (s->has_write_zeroes) {
127
int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE,
128
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_write_zeroes_unmap(void *opaque)
129
}
130
#endif
131
132
-#ifdef CONFIG_XFS
133
- if (s->is_xfs) {
134
- /* xfs_discard() guarantees that the discarded area reads as all-zero
135
- * afterwards, so we can use it here. */
136
- return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
137
- }
138
-#endif
139
-
140
/* If we couldn't manage to unmap while guaranteed that the area reads as
141
* all-zero afterwards, just write zeroes without unmapping */
142
ret = handle_aiocb_write_zeroes(aiocb);
143
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_discard(void *opaque)
144
ret = -errno;
145
#endif
146
} else {
147
-#ifdef CONFIG_XFS
148
- if (s->is_xfs) {
149
- return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
150
- }
151
-#endif
152
-
153
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
154
ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
155
aiocb->aio_offset, aiocb->aio_nbytes);
156
--
51
--
157
2.20.1
52
2.13.6
158
53
159
54
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
3
chmod a-w don't help under root, so skip the test in such case.
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Fam Zheng <famz@redhat.com>
7
---
3
---
8
tests/qemu-iotests/232 | 6 ++++++
4
block/io.c | 6 ++++++
9
1 file changed, 6 insertions(+)
5
1 file changed, 6 insertions(+)
10
6
11
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
7
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100755
8
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/232
9
--- a/block/io.c
14
+++ b/tests/qemu-iotests/232
10
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ if [ -n "$TEST_IMG_FILE" ]; then
11
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
16
TEST_IMG=$TEST_IMG_FILE
12
BdrvNextIterator it;
17
fi
13
GSList *aio_ctxs = NULL, *ctx;
18
14
19
+chmod a-w $TEST_IMG
15
+ /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread
20
+(echo test > $TEST_IMG) 2>/dev/null && \
16
+ * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on
21
+ _notrun "Readonly attribute is ignored, probably you run this test as" \
17
+ * nodes in several different AioContexts, so make sure we're in the main
22
+ "root, which is unsupported."
18
+ * context. */
23
+chmod a+w $TEST_IMG
19
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
24
+
20
+
25
echo
21
block_job_pause_all();
26
echo "=== -drive with read-write image: read-only/auto-read-only combinations ==="
22
27
echo
23
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
28
--
24
--
29
2.20.1
25
2.13.6
30
26
31
27
diff view generated by jsdifflib
1
If QEMU_AIO_NO_FALLBACK is given, we always return failure and don't
1
bdrv_drained_begin() doesn't increase bs->quiesce_counter recursively
2
even try to use the BLKZEROOUT ioctl. In this failure case, we shouldn't
2
and also doesn't notify other parent nodes of children, which both means
3
disable has_write_zeroes because we didn't learn anything about the
3
that the child nodes are not actually drained, and bdrv_drained_begin()
4
ioctl. The next request might not set QEMU_AIO_NO_FALLBACK and we can
4
is providing useful functionality only on a single node.
5
still use the ioctl then.
6
5
7
Fixes: 738301e1175
6
To keep things consistent, we also shouldn't call the block driver
8
Reported-by: Eric Blake <eblake@redhat.com>
7
callbacks recursively.
8
9
A proper recursive drain version that provides an actually working
10
drained section for child nodes will be introduced later.
11
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
11
---
14
---
12
block/file-posix.c | 6 +++---
15
block/io.c | 16 +++++++++-------
13
1 file changed, 3 insertions(+), 3 deletions(-)
16
1 file changed, 9 insertions(+), 7 deletions(-)
14
17
15
diff --git a/block/file-posix.c b/block/file-posix.c
18
diff --git a/block/io.c b/block/io.c
16
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
17
--- a/block/file-posix.c
20
--- a/block/io.c
18
+++ b/block/file-posix.c
21
+++ b/block/io.c
19
@@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb)
22
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
20
} while (errno == EINTR);
23
}
21
24
22
ret = translate_err(-errno);
25
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
23
+ if (ret == -ENOTSUP) {
26
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
24
+ s->has_write_zeroes = false;
27
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive)
28
{
29
BdrvChild *child, *tmp;
30
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
31
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
32
bdrv_coroutine_enter(bs, data.co);
33
BDRV_POLL_WHILE(bs, !data.done);
34
35
- QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
36
- bdrv_drain_invoke(child->bs, begin);
37
+ if (recursive) {
38
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
39
+ bdrv_drain_invoke(child->bs, begin, true);
25
+ }
40
+ }
26
}
41
}
27
#endif
28
29
- if (ret == -ENOTSUP) {
30
- s->has_write_zeroes = false;
31
- }
32
return ret;
33
}
42
}
34
43
44
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
45
bdrv_parent_drained_begin(bs);
46
}
47
48
- bdrv_drain_invoke(bs, true);
49
+ bdrv_drain_invoke(bs, true, false);
50
bdrv_drain_recurse(bs);
51
}
52
53
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
54
}
55
56
/* Re-enable things in child-to-parent order */
57
- bdrv_drain_invoke(bs, false);
58
+ bdrv_drain_invoke(bs, false, false);
59
bdrv_parent_drained_end(bs);
60
aio_enable_external(bdrv_get_aio_context(bs));
61
}
62
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
63
aio_context_acquire(aio_context);
64
aio_disable_external(aio_context);
65
bdrv_parent_drained_begin(bs);
66
- bdrv_drain_invoke(bs, true);
67
+ bdrv_drain_invoke(bs, true, true);
68
aio_context_release(aio_context);
69
70
if (!g_slist_find(aio_ctxs, aio_context)) {
71
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
72
73
/* Re-enable things in child-to-parent order */
74
aio_context_acquire(aio_context);
75
- bdrv_drain_invoke(bs, false);
76
+ bdrv_drain_invoke(bs, false, true);
77
bdrv_parent_drained_end(bs);
78
aio_enable_external(aio_context);
79
aio_context_release(aio_context);
35
--
80
--
36
2.20.1
81
2.13.6
37
82
38
83
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
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.
2
5
3
The Valgrind uses the exported variable TMPDIR and fails if the
6
Also, add a backing file to the test node to test whether the operations
4
directory does not exist. Let us exclude such a test case from
7
work recursively.
5
being run under the Valgrind and notify the user of it.
6
8
7
Suggested-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
9
Reviewed-by: John Snow <jsnow@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
10
---
12
tests/qemu-iotests/051 | 4 ++++
11
tests/test-bdrv-drain.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-----
13
1 file changed, 4 insertions(+)
12
1 file changed, 62 insertions(+), 7 deletions(-)
14
13
15
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
16
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/051
16
--- a/tests/test-bdrv-drain.c
18
+++ b/tests/qemu-iotests/051
17
+++ b/tests/test-bdrv-drain.c
19
@@ -XXX,XX +XXX,XX @@ printf %b "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id\n" |
18
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = {
20
$QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io
19
21
20
.bdrv_co_drain_begin = bdrv_test_co_drain_begin,
22
# Using snapshot=on with a non-existent TMPDIR
21
.bdrv_co_drain_end = bdrv_test_co_drain_end,
23
+if [ "${VALGRIND_QEMU_VM}" == "y" ]; then
22
+
24
+ _casenotrun "Valgrind needs a valid TMPDIR for itself"
23
+ .bdrv_child_perm = bdrv_format_default_perms,
25
+fi
24
};
26
+VALGRIND_QEMU_VM= \
25
27
TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on
26
static void aio_ret_cb(void *opaque, int ret)
28
27
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
29
# Using snapshot=on together with read-only=on
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
}
30
--
136
--
31
2.20.1
137
2.13.6
32
138
33
139
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
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.
2
4
3
The new function _casenotrun() is to be invoked if a test case cannot
4
be run for some reason. The user will be notified by a message passed
5
to the function. It is the caller's responsibility to make skipped a
6
particular test.
7
8
Suggested-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
11
Reviewed-by: Cleber Rosa <crosa@redhat.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/common.rc | 9 +++++++++
7
tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
15
1 file changed, 9 insertions(+)
8
1 file changed, 45 insertions(+)
16
9
17
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
18
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/common.rc
12
--- a/tests/test-bdrv-drain.c
20
+++ b/tests/qemu-iotests/common.rc
13
+++ b/tests/test-bdrv-drain.c
21
@@ -XXX,XX +XXX,XX @@ _notrun()
14
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
22
exit
15
test_drv_cb_common(BDRV_DRAIN, false);
23
}
16
}
24
17
25
+# bail out, setting up .casenotrun file
18
+static void test_quiesce_common(enum drain_type drain_type, bool recursive)
26
+# The function _casenotrun() is used as a notifier. It is the
27
+# caller's responsibility to make skipped a particular test.
28
+#
29
+_casenotrun()
30
+{
19
+{
31
+ echo " [case not run] $*" >>"$OUTPUT_DIR/$seq.casenotrun"
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);
32
+}
47
+}
33
+
48
+
34
# just plain bail out
49
+static void test_quiesce_drain_all(void)
35
#
50
+{
36
_fail()
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
}
37
--
72
--
38
2.20.1
73
2.13.6
39
74
40
75
diff view generated by jsdifflib
1
From: Peter Lieven <pl@kamp.de>
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.
2
5
3
libnfs recently added support for unmounting. Add support
6
This implements .drained_begin/end callbacks in child_job in order to
4
in Qemu too.
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.
5
10
6
Signed-off-by: Peter Lieven <pl@kamp.de>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
12
---
9
block/nfs.c | 5 ++++-
13
blockjob.c | 22 +++++++++-------------
10
1 file changed, 4 insertions(+), 1 deletion(-)
14
1 file changed, 9 insertions(+), 13 deletions(-)
11
15
12
diff --git a/block/nfs.c b/block/nfs.c
16
diff --git a/blockjob.c b/blockjob.c
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/block/nfs.c
18
--- a/blockjob.c
15
+++ b/block/nfs.c
19
+++ b/blockjob.c
16
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static char *child_job_get_parent_desc(BdrvChild *c)
17
/*
21
job->id);
18
* QEMU Block driver for native access to files on NFS shares
22
}
19
*
23
20
- * Copyright (c) 2014-2017 Peter Lieven <pl@kamp.de>
24
-static const BdrvChildRole child_job = {
21
+ * Copyright (c) 2014-2019 Peter Lieven <pl@kamp.de>
25
- .get_parent_desc = child_job_get_parent_desc,
22
*
26
- .stay_at_node = true,
23
* Permission is hereby granted, free of charge, to any person obtaining a copy
27
-};
24
* of this software and associated documentation files (the "Software"), to deal
28
-
25
@@ -XXX,XX +XXX,XX @@ static void nfs_client_close(NFSClient *client)
29
-static void block_job_drained_begin(void *opaque)
26
nfs_close(client->context, client->fh);
30
+static void child_job_drained_begin(BdrvChild *c)
27
client->fh = NULL;
31
{
28
}
32
- BlockJob *job = opaque;
29
+#ifdef LIBNFS_FEATURE_UMOUNT
33
+ BlockJob *job = c->opaque;
30
+ nfs_umount(client->context);
34
block_job_pause(job);
31
+#endif
35
}
32
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
36
33
false, NULL, NULL, NULL, NULL);
37
-static void block_job_drained_end(void *opaque)
34
nfs_destroy_context(client->context);
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);
35
--
64
--
36
2.20.1
65
2.13.6
37
66
38
67
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Block jobs must be paused if any of the involved nodes are drained.
2
2
3
We have two Python unittest-style tests that test NBD. As such, they
4
should specify supported_protocols=['nbd'] so they are skipped when the
5
user wants to test some other protocol.
6
7
Furthermore, we should restrict their choice of formats to 'raw'. The
8
idea of a protocol/format combination is to use some format over some
9
protocol; but we always use the raw format over NBD. It does not really
10
matter what the NBD server uses on its end, and it is not a useful test
11
of the respective format driver anyway.
12
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
4
---
16
tests/qemu-iotests/147 | 5 ++---
5
tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++
17
tests/qemu-iotests/205 | 3 ++-
6
1 file changed, 121 insertions(+)
18
2 files changed, 4 insertions(+), 4 deletions(-)
19
7
20
diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
21
index XXXXXXX..XXXXXXX 100755
9
index XXXXXXX..XXXXXXX 100644
22
--- a/tests/qemu-iotests/147
10
--- a/tests/test-bdrv-drain.c
23
+++ b/tests/qemu-iotests/147
11
+++ b/tests/test-bdrv-drain.c
24
@@ -XXX,XX +XXX,XX @@ class BuiltinNBD(NBDBlockdevAddBase):
12
@@ -XXX,XX +XXX,XX @@
25
13
26
14
#include "qemu/osdep.h"
27
if __name__ == '__main__':
15
#include "block/block.h"
28
- # Need to support image creation
16
+#include "block/blockjob_int.h"
29
- iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
17
#include "sysemu/block-backend.h"
30
- 'vmdk', 'raw', 'vhdx', 'qed'])
18
#include "qapi/error.h"
31
+ iotests.main(supported_fmts=['raw'],
19
32
+ supported_protocols=['nbd'])
20
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
33
diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205
21
test_quiesce_common(BDRV_DRAIN, false);
34
index XXXXXXX..XXXXXXX 100755
22
}
35
--- a/tests/qemu-iotests/205
23
36
+++ b/tests/qemu-iotests/205
24
+
37
@@ -XXX,XX +XXX,XX @@ class TestNbdServerRemove(iotests.QMPTestCase):
25
+typedef struct TestBlockJob {
38
26
+ BlockJob common;
39
27
+ bool should_complete;
40
if __name__ == '__main__':
28
+} TestBlockJob;
41
- iotests.main(supported_fmts=['generic'])
29
+
42
+ iotests.main(supported_fmts=['raw'],
30
+static void test_job_completed(BlockJob *job, void *opaque)
43
+ supported_protocols=['nbd'])
31
+{
32
+ block_job_completed(job, 0);
33
+}
34
+
35
+static void coroutine_fn test_job_start(void *opaque)
36
+{
37
+ TestBlockJob *s = opaque;
38
+
39
+ while (!s->should_complete) {
40
+ block_job_sleep_ns(&s->common, 100000);
41
+ }
42
+
43
+ block_job_defer_to_main_loop(&s->common, test_job_completed, NULL);
44
+}
45
+
46
+static void test_job_complete(BlockJob *job, Error **errp)
47
+{
48
+ TestBlockJob *s = container_of(job, TestBlockJob, common);
49
+ s->should_complete = true;
50
+}
51
+
52
+BlockJobDriver test_job_driver = {
53
+ .instance_size = sizeof(TestBlockJob),
54
+ .start = test_job_start,
55
+ .complete = test_job_complete,
56
+};
57
+
58
+static void test_blockjob_common(enum drain_type drain_type)
59
+{
60
+ BlockBackend *blk_src, *blk_target;
61
+ BlockDriverState *src, *target;
62
+ BlockJob *job;
63
+ int ret;
64
+
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
}
44
--
153
--
45
2.20.1
154
2.13.6
46
155
47
156
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
Block jobs are already paused using the BdrvChildRole drain callbacks,
2
so we don't need an additional block_job_pause_all() call.
2
3
3
In job_finish_sync job_enter should be enough for a job to make some
4
progress and draining is a wrong tool for it. So use job_enter directly
5
here and drop job_drain with all related staff not used more.
6
7
Suggested-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Tested-by: John Snow <jsnow@redhat.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
5
---
13
include/block/blockjob_int.h | 19 -------------------
6
block/io.c | 4 ----
14
include/qemu/job.h | 13 -------------
7
tests/test-bdrv-drain.c | 10 ++++------
15
block/backup.c | 19 +------------------
8
2 files changed, 4 insertions(+), 10 deletions(-)
16
block/commit.c | 1 -
17
block/mirror.c | 28 +++-------------------------
18
block/stream.c | 1 -
19
blockjob.c | 13 -------------
20
job.c | 12 +-----------
21
tests/test-bdrv-drain.c | 3 ---
22
tests/test-block-iothread.c | 1 -
23
tests/test-blockjob-txn.c | 1 -
24
tests/test-blockjob.c | 2 --
25
12 files changed, 5 insertions(+), 108 deletions(-)
26
9
27
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
10
diff --git a/block/io.c b/block/io.c
28
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/blockjob_int.h
12
--- a/block/io.c
30
+++ b/include/block/blockjob_int.h
13
+++ b/block/io.c
31
@@ -XXX,XX +XXX,XX @@ struct BlockJobDriver {
14
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
32
* besides job->blk to the new AioContext.
15
* context. */
33
*/
16
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
34
void (*attached_aio_context)(BlockJob *job, AioContext *new_context);
17
18
- block_job_pause_all();
35
-
19
-
36
- /*
20
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
37
- * If the callback is not NULL, it will be invoked when the job has to be
21
AioContext *aio_context = bdrv_get_aio_context(bs);
38
- * synchronously cancelled or completed; it should drain BlockDriverStates
22
39
- * as required to ensure progress.
23
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
40
- *
24
aio_enable_external(aio_context);
41
- * Block jobs must use the default implementation for job_driver.drain,
25
aio_context_release(aio_context);
42
- * which will in turn call this callback after doing generic block job
26
}
43
- * stuff.
44
- */
45
- void (*drain)(BlockJob *job);
46
};
47
48
/**
49
@@ -XXX,XX +XXX,XX @@ void block_job_free(Job *job);
50
*/
51
void block_job_user_resume(Job *job);
52
53
-/**
54
- * block_job_drain:
55
- * Callback to be used for JobDriver.drain in all block jobs. Drains the main
56
- * block node associated with the block jobs and calls BlockJobDriver.drain for
57
- * job-specific actions.
58
- */
59
-void block_job_drain(Job *job);
60
-
27
-
61
/**
28
- block_job_resume_all();
62
* block_job_ratelimit_get_delay:
63
*
64
diff --git a/include/qemu/job.h b/include/qemu/job.h
65
index XXXXXXX..XXXXXXX 100644
66
--- a/include/qemu/job.h
67
+++ b/include/qemu/job.h
68
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
69
*/
70
void (*complete)(Job *job, Error **errp);
71
72
- /*
73
- * If the callback is not NULL, it will be invoked when the job has to be
74
- * synchronously cancelled or completed; it should drain any activities
75
- * as required to ensure progress.
76
- */
77
- void (*drain)(Job *job);
78
-
79
/**
80
* If the callback is not NULL, prepare will be invoked when all the jobs
81
* belonging to the same transaction complete; or upon this job's completion
82
@@ -XXX,XX +XXX,XX @@ bool job_user_paused(Job *job);
83
*/
84
void job_user_resume(Job *job, Error **errp);
85
86
-/*
87
- * Drain any activities as required to ensure progress. This can be called in a
88
- * loop to synchronously complete a job.
89
- */
90
-void job_drain(Job *job);
91
-
92
/**
93
* Get the next element from the list of block jobs after @job, or the
94
* first one if @job is %NULL.
95
diff --git a/block/backup.c b/block/backup.c
96
index XXXXXXX..XXXXXXX 100644
97
--- a/block/backup.c
98
+++ b/block/backup.c
99
@@ -XXX,XX +XXX,XX @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
100
bdrv_set_dirty_bitmap(backup_job->copy_bitmap, 0, backup_job->len);
101
}
29
}
102
30
103
-static void backup_drain(BlockJob *job)
31
void bdrv_drain_all(void)
104
-{
105
- BackupBlockJob *s = container_of(job, BackupBlockJob, common);
106
-
107
- /* Need to keep a reference in case blk_drain triggers execution
108
- * of backup_complete...
109
- */
110
- if (s->target) {
111
- BlockBackend *target = s->target;
112
- blk_ref(target);
113
- blk_drain(target);
114
- blk_unref(target);
115
- }
116
-}
117
-
118
static BlockErrorAction backup_error_action(BackupBlockJob *job,
119
bool read, int error)
120
{
121
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver backup_job_driver = {
122
.job_type = JOB_TYPE_BACKUP,
123
.free = block_job_free,
124
.user_resume = block_job_user_resume,
125
- .drain = block_job_drain,
126
.run = backup_run,
127
.commit = backup_commit,
128
.abort = backup_abort,
129
.clean = backup_clean,
130
- },
131
- .drain = backup_drain,
132
+ }
133
};
134
135
static int64_t backup_calculate_cluster_size(BlockDriverState *target,
136
diff --git a/block/commit.c b/block/commit.c
137
index XXXXXXX..XXXXXXX 100644
138
--- a/block/commit.c
139
+++ b/block/commit.c
140
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_job_driver = {
141
.job_type = JOB_TYPE_COMMIT,
142
.free = block_job_free,
143
.user_resume = block_job_user_resume,
144
- .drain = block_job_drain,
145
.run = commit_run,
146
.prepare = commit_prepare,
147
.abort = commit_abort,
148
diff --git a/block/mirror.c b/block/mirror.c
149
index XXXXXXX..XXXXXXX 100644
150
--- a/block/mirror.c
151
+++ b/block/mirror.c
152
@@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job)
153
bdrv_ref(mirror_top_bs);
154
bdrv_ref(target_bs);
155
156
- /* Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
157
+ /*
158
+ * Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
159
* inserting target_bs at s->to_replace, where we might not be able to get
160
* these permissions.
161
- *
162
- * Note that blk_unref() alone doesn't necessarily drop permissions because
163
- * we might be running nested inside mirror_drain(), which takes an extra
164
- * reference, so use an explicit blk_set_perm() first. */
165
- blk_set_perm(s->target, 0, BLK_PERM_ALL, &error_abort);
166
+ */
167
blk_unref(s->target);
168
s->target = NULL;
169
170
@@ -XXX,XX +XXX,XX @@ static bool mirror_drained_poll(BlockJob *job)
171
return !!s->in_flight;
172
}
173
174
-static void mirror_drain(BlockJob *job)
175
-{
176
- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
177
-
178
- /* Need to keep a reference in case blk_drain triggers execution
179
- * of mirror_complete...
180
- */
181
- if (s->target) {
182
- BlockBackend *target = s->target;
183
- blk_ref(target);
184
- blk_drain(target);
185
- blk_unref(target);
186
- }
187
-}
188
-
189
static const BlockJobDriver mirror_job_driver = {
190
.job_driver = {
191
.instance_size = sizeof(MirrorBlockJob),
192
.job_type = JOB_TYPE_MIRROR,
193
.free = block_job_free,
194
.user_resume = block_job_user_resume,
195
- .drain = block_job_drain,
196
.run = mirror_run,
197
.prepare = mirror_prepare,
198
.abort = mirror_abort,
199
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
200
.complete = mirror_complete,
201
},
202
.drained_poll = mirror_drained_poll,
203
- .drain = mirror_drain,
204
};
205
206
static const BlockJobDriver commit_active_job_driver = {
207
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
208
.job_type = JOB_TYPE_COMMIT,
209
.free = block_job_free,
210
.user_resume = block_job_user_resume,
211
- .drain = block_job_drain,
212
.run = mirror_run,
213
.prepare = mirror_prepare,
214
.abort = mirror_abort,
215
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
216
.complete = mirror_complete,
217
},
218
.drained_poll = mirror_drained_poll,
219
- .drain = mirror_drain,
220
};
221
222
static void coroutine_fn
223
diff --git a/block/stream.c b/block/stream.c
224
index XXXXXXX..XXXXXXX 100644
225
--- a/block/stream.c
226
+++ b/block/stream.c
227
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver stream_job_driver = {
228
.abort = stream_abort,
229
.clean = stream_clean,
230
.user_resume = block_job_user_resume,
231
- .drain = block_job_drain,
232
},
233
};
234
235
diff --git a/blockjob.c b/blockjob.c
236
index XXXXXXX..XXXXXXX 100644
237
--- a/blockjob.c
238
+++ b/blockjob.c
239
@@ -XXX,XX +XXX,XX @@ void block_job_free(Job *job)
240
error_free(bjob->blocker);
241
}
242
243
-void block_job_drain(Job *job)
244
-{
245
- BlockJob *bjob = container_of(job, BlockJob, job);
246
- const JobDriver *drv = job->driver;
247
- BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver);
248
-
249
- blk_drain(bjob->blk);
250
- if (bjdrv->drain) {
251
- bjdrv->drain(bjob);
252
- }
253
-}
254
-
255
static char *child_job_get_parent_desc(BdrvChild *c)
256
{
257
BlockJob *job = c->opaque;
258
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
259
assert(is_block_job(&job->job));
260
assert(job->job.driver->free == &block_job_free);
261
assert(job->job.driver->user_resume == &block_job_user_resume);
262
- assert(job->job.driver->drain == &block_job_drain);
263
264
job->blk = blk;
265
266
diff --git a/job.c b/job.c
267
index XXXXXXX..XXXXXXX 100644
268
--- a/job.c
269
+++ b/job.c
270
@@ -XXX,XX +XXX,XX @@ void coroutine_fn job_sleep_ns(Job *job, int64_t ns)
271
job_pause_point(job);
272
}
273
274
-void job_drain(Job *job)
275
-{
276
- /* If job is !busy this kicks it into the next pause point. */
277
- job_enter(job);
278
-
279
- if (job->driver->drain) {
280
- job->driver->drain(job);
281
- }
282
-}
283
-
284
/* Assumes the block_job_mutex is held */
285
static bool job_timer_not_pending(Job *job)
286
{
287
@@ -XXX,XX +XXX,XX @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
288
}
289
290
AIO_WAIT_WHILE(job->aio_context,
291
- (job_drain(job), !job_is_completed(job)));
292
+ (job_enter(job), !job_is_completed(job)));
293
294
ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret;
295
job_unref(job);
296
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
32
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
297
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
298
--- a/tests/test-bdrv-drain.c
34
--- a/tests/test-bdrv-drain.c
299
+++ b/tests/test-bdrv-drain.c
35
+++ b/tests/test-bdrv-drain.c
300
@@ -XXX,XX +XXX,XX @@ BlockJobDriver test_job_driver = {
36
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
301
.instance_size = sizeof(TestBlockJob),
37
do_drain_begin(drain_type, src);
302
.free = block_job_free,
38
303
.user_resume = block_job_user_resume,
39
if (drain_type == BDRV_DRAIN_ALL) {
304
- .drain = block_job_drain,
40
- /* bdrv_drain_all() drains both src and target, and involves an
305
.run = test_job_run,
41
- * additional block_job_pause_all() */
306
.complete = test_job_complete,
42
- g_assert_cmpint(job->pause_count, ==, 3);
307
.prepare = test_job_prepare,
43
+ /* bdrv_drain_all() drains both src and target */
308
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_drop_backing_job_driver = {
44
+ g_assert_cmpint(job->pause_count, ==, 2);
309
.instance_size = sizeof(TestDropBackingBlockJob),
45
} else {
310
.free = block_job_free,
46
g_assert_cmpint(job->pause_count, ==, 1);
311
.user_resume = block_job_user_resume,
312
- .drain = block_job_drain,
313
.run = test_drop_backing_job_run,
314
.commit = test_drop_backing_job_commit,
315
}
47
}
316
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_simple_job_driver = {
48
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
317
.instance_size = sizeof(TestSimpleBlockJob),
49
do_drain_begin(drain_type, target);
318
.free = block_job_free,
50
319
.user_resume = block_job_user_resume,
51
if (drain_type == BDRV_DRAIN_ALL) {
320
- .drain = block_job_drain,
52
- /* bdrv_drain_all() drains both src and target, and involves an
321
.run = test_simple_job_run,
53
- * additional block_job_pause_all() */
322
.clean = test_simple_job_clean,
54
- g_assert_cmpint(job->pause_count, ==, 3);
323
},
55
+ /* bdrv_drain_all() drains both src and target */
324
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
56
+ g_assert_cmpint(job->pause_count, ==, 2);
325
index XXXXXXX..XXXXXXX 100644
57
} else {
326
--- a/tests/test-block-iothread.c
58
g_assert_cmpint(job->pause_count, ==, 1);
327
+++ b/tests/test-block-iothread.c
59
}
328
@@ -XXX,XX +XXX,XX @@ BlockJobDriver test_job_driver = {
329
.instance_size = sizeof(TestBlockJob),
330
.free = block_job_free,
331
.user_resume = block_job_user_resume,
332
- .drain = block_job_drain,
333
.run = test_job_run,
334
.complete = test_job_complete,
335
.prepare = test_job_prepare,
336
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
337
index XXXXXXX..XXXXXXX 100644
338
--- a/tests/test-blockjob-txn.c
339
+++ b/tests/test-blockjob-txn.c
340
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_block_job_driver = {
341
.instance_size = sizeof(TestBlockJob),
342
.free = block_job_free,
343
.user_resume = block_job_user_resume,
344
- .drain = block_job_drain,
345
.run = test_block_job_run,
346
.clean = test_block_job_clean,
347
},
348
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
349
index XXXXXXX..XXXXXXX 100644
350
--- a/tests/test-blockjob.c
351
+++ b/tests/test-blockjob.c
352
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_block_job_driver = {
353
.instance_size = sizeof(BlockJob),
354
.free = block_job_free,
355
.user_resume = block_job_user_resume,
356
- .drain = block_job_drain,
357
},
358
};
359
360
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_cancel_driver = {
361
.instance_size = sizeof(CancelJob),
362
.free = block_job_free,
363
.user_resume = block_job_user_resume,
364
- .drain = block_job_drain,
365
.run = cancel_job_run,
366
.complete = cancel_job_complete,
367
},
368
--
60
--
369
2.20.1
61
2.13.6
370
62
371
63
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
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.
2
6
3
Most of our Python unittest-style tests only support the file protocol.
4
You can run them with any other protocol, but the test will simply
5
ignore your choice and use file anyway.
6
7
We should let them signal that they require the file protocol so they
8
are skipped when you want to test some other protocol.
9
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
8
---
13
tests/qemu-iotests/030 | 3 ++-
9
block/io.c | 12 +++++++-----
14
tests/qemu-iotests/040 | 3 ++-
10
1 file changed, 7 insertions(+), 5 deletions(-)
15
tests/qemu-iotests/041 | 3 ++-
16
tests/qemu-iotests/044 | 3 ++-
17
tests/qemu-iotests/045 | 3 ++-
18
tests/qemu-iotests/055 | 3 ++-
19
tests/qemu-iotests/056 | 3 ++-
20
tests/qemu-iotests/057 | 3 ++-
21
tests/qemu-iotests/065 | 3 ++-
22
tests/qemu-iotests/096 | 3 ++-
23
tests/qemu-iotests/118 | 3 ++-
24
tests/qemu-iotests/124 | 3 ++-
25
tests/qemu-iotests/129 | 3 ++-
26
tests/qemu-iotests/132 | 3 ++-
27
tests/qemu-iotests/139 | 3 ++-
28
tests/qemu-iotests/148 | 3 ++-
29
tests/qemu-iotests/151 | 3 ++-
30
tests/qemu-iotests/152 | 3 ++-
31
tests/qemu-iotests/155 | 3 ++-
32
tests/qemu-iotests/163 | 3 ++-
33
tests/qemu-iotests/165 | 3 ++-
34
tests/qemu-iotests/169 | 3 ++-
35
tests/qemu-iotests/196 | 3 ++-
36
tests/qemu-iotests/199 | 3 ++-
37
tests/qemu-iotests/245 | 3 ++-
38
tests/qemu-iotests/257 | 3 ++-
39
26 files changed, 52 insertions(+), 26 deletions(-)
40
11
41
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
12
diff --git a/block/io.c b/block/io.c
42
index XXXXXXX..XXXXXXX 100755
43
--- a/tests/qemu-iotests/030
44
+++ b/tests/qemu-iotests/030
45
@@ -XXX,XX +XXX,XX @@ class TestSetSpeed(iotests.QMPTestCase):
46
self.cancel_and_wait(resume=True)
47
48
if __name__ == '__main__':
49
- iotests.main(supported_fmts=['qcow2', 'qed'])
50
+ iotests.main(supported_fmts=['qcow2', 'qed'],
51
+ supported_protocols=['file'])
52
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
53
index XXXXXXX..XXXXXXX 100755
54
--- a/tests/qemu-iotests/040
55
+++ b/tests/qemu-iotests/040
56
@@ -XXX,XX +XXX,XX @@ class TestReopenOverlay(ImageCommitTestCase):
57
self.run_commit_test(self.img1, self.img0)
58
59
if __name__ == '__main__':
60
- iotests.main(supported_fmts=['qcow2', 'qed'])
61
+ iotests.main(supported_fmts=['qcow2', 'qed'],
62
+ supported_protocols=['file'])
63
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
64
index XXXXXXX..XXXXXXX 100755
65
--- a/tests/qemu-iotests/041
66
+++ b/tests/qemu-iotests/041
67
@@ -XXX,XX +XXX,XX @@ class TestOrphanedSource(iotests.QMPTestCase):
68
self.assert_qmp(result, 'error/class', 'GenericError')
69
70
if __name__ == '__main__':
71
- iotests.main(supported_fmts=['qcow2', 'qed'])
72
+ iotests.main(supported_fmts=['qcow2', 'qed'],
73
+ supported_protocols=['file'])
74
diff --git a/tests/qemu-iotests/044 b/tests/qemu-iotests/044
75
index XXXXXXX..XXXXXXX 100755
76
--- a/tests/qemu-iotests/044
77
+++ b/tests/qemu-iotests/044
78
@@ -XXX,XX +XXX,XX @@ class TestRefcountTableGrowth(iotests.QMPTestCase):
79
pass
80
81
if __name__ == '__main__':
82
- iotests.main(supported_fmts=['qcow2'])
83
+ iotests.main(supported_fmts=['qcow2'],
84
+ supported_protocols=['file'])
85
diff --git a/tests/qemu-iotests/045 b/tests/qemu-iotests/045
86
index XXXXXXX..XXXXXXX 100755
87
--- a/tests/qemu-iotests/045
88
+++ b/tests/qemu-iotests/045
89
@@ -XXX,XX +XXX,XX @@ class TestSCMFd(iotests.QMPTestCase):
90
"File descriptor named '%s' not found" % fdname)
91
92
if __name__ == '__main__':
93
- iotests.main(supported_fmts=['raw'])
94
+ iotests.main(supported_fmts=['raw'],
95
+ supported_protocols=['file'])
96
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
97
index XXXXXXX..XXXXXXX 100755
98
--- a/tests/qemu-iotests/055
99
+++ b/tests/qemu-iotests/055
100
@@ -XXX,XX +XXX,XX @@ class TestDriveCompression(iotests.QMPTestCase):
101
target='drive1')
102
103
if __name__ == '__main__':
104
- iotests.main(supported_fmts=['raw', 'qcow2'])
105
+ iotests.main(supported_fmts=['raw', 'qcow2'],
106
+ supported_protocols=['file'])
107
diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056
108
index XXXXXXX..XXXXXXX 100755
109
--- a/tests/qemu-iotests/056
110
+++ b/tests/qemu-iotests/056
111
@@ -XXX,XX +XXX,XX @@ class BackupTest(iotests.QMPTestCase):
112
self.dismissal_failure(True)
113
114
if __name__ == '__main__':
115
- iotests.main(supported_fmts=['qcow2', 'qed'])
116
+ iotests.main(supported_fmts=['qcow2', 'qed'],
117
+ supported_protocols=['file'])
118
diff --git a/tests/qemu-iotests/057 b/tests/qemu-iotests/057
119
index XXXXXXX..XXXXXXX 100755
120
--- a/tests/qemu-iotests/057
121
+++ b/tests/qemu-iotests/057
122
@@ -XXX,XX +XXX,XX @@ class TestSnapshotDelete(ImageSnapshotTestCase):
123
self.assert_qmp(result, 'error/class', 'GenericError')
124
125
if __name__ == '__main__':
126
- iotests.main(supported_fmts=['qcow2'])
127
+ iotests.main(supported_fmts=['qcow2'],
128
+ supported_protocols=['file'])
129
diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065
130
index XXXXXXX..XXXXXXX 100755
131
--- a/tests/qemu-iotests/065
132
+++ b/tests/qemu-iotests/065
133
@@ -XXX,XX +XXX,XX @@ TestQemuImgInfo = None
134
TestQMP = None
135
136
if __name__ == '__main__':
137
- iotests.main(supported_fmts=['qcow2'])
138
+ iotests.main(supported_fmts=['qcow2'],
139
+ supported_protocols=['file'])
140
diff --git a/tests/qemu-iotests/096 b/tests/qemu-iotests/096
141
index XXXXXXX..XXXXXXX 100755
142
--- a/tests/qemu-iotests/096
143
+++ b/tests/qemu-iotests/096
144
@@ -XXX,XX +XXX,XX @@ class TestLiveSnapshot(iotests.QMPTestCase):
145
self.checkConfig('target')
146
147
if __name__ == '__main__':
148
- iotests.main(supported_fmts=['qcow2'])
149
+ iotests.main(supported_fmts=['qcow2'],
150
+ supported_protocols=['file'])
151
diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118
152
index XXXXXXX..XXXXXXX 100755
153
--- a/tests/qemu-iotests/118
154
+++ b/tests/qemu-iotests/118
155
@@ -XXX,XX +XXX,XX @@ if __name__ == '__main__':
156
iotests.qemu_default_machine)
157
# Need to support image creation
158
iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
159
- 'vmdk', 'raw', 'vhdx', 'qed'])
160
+ 'vmdk', 'raw', 'vhdx', 'qed'],
161
+ supported_protocols=['file'])
162
diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124
163
index XXXXXXX..XXXXXXX 100755
164
--- a/tests/qemu-iotests/124
165
+++ b/tests/qemu-iotests/124
166
@@ -XXX,XX +XXX,XX @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
167
168
169
if __name__ == '__main__':
170
- iotests.main(supported_fmts=['qcow2'])
171
+ iotests.main(supported_fmts=['qcow2'],
172
+ supported_protocols=['file'])
173
diff --git a/tests/qemu-iotests/129 b/tests/qemu-iotests/129
174
index XXXXXXX..XXXXXXX 100755
175
--- a/tests/qemu-iotests/129
176
+++ b/tests/qemu-iotests/129
177
@@ -XXX,XX +XXX,XX @@ class TestStopWithBlockJob(iotests.QMPTestCase):
178
self.do_test_stop("block-commit", device="drive0")
179
180
if __name__ == '__main__':
181
- iotests.main(supported_fmts=["qcow2"])
182
+ iotests.main(supported_fmts=["qcow2"],
183
+ supported_protocols=["file"])
184
diff --git a/tests/qemu-iotests/132 b/tests/qemu-iotests/132
185
index XXXXXXX..XXXXXXX 100755
186
--- a/tests/qemu-iotests/132
187
+++ b/tests/qemu-iotests/132
188
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
189
'target image does not match source after mirroring')
190
191
if __name__ == '__main__':
192
- iotests.main(supported_fmts=['raw', 'qcow2'])
193
+ iotests.main(supported_fmts=['raw', 'qcow2'],
194
+ supported_protocols=['file'])
195
diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139
196
index XXXXXXX..XXXXXXX 100755
197
--- a/tests/qemu-iotests/139
198
+++ b/tests/qemu-iotests/139
199
@@ -XXX,XX +XXX,XX @@ class TestBlockdevDel(iotests.QMPTestCase):
200
201
202
if __name__ == '__main__':
203
- iotests.main(supported_fmts=["qcow2"])
204
+ iotests.main(supported_fmts=["qcow2"],
205
+ supported_protocols=["file"])
206
diff --git a/tests/qemu-iotests/148 b/tests/qemu-iotests/148
207
index XXXXXXX..XXXXXXX 100755
208
--- a/tests/qemu-iotests/148
209
+++ b/tests/qemu-iotests/148
210
@@ -XXX,XX +XXX,XX @@ class TestFifoQuorumEvents(TestQuorumEvents):
211
212
if __name__ == '__main__':
213
iotests.verify_quorum()
214
- iotests.main(supported_fmts=["raw"])
215
+ iotests.main(supported_fmts=["raw"],
216
+ supported_protocols=["file"])
217
diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151
218
index XXXXXXX..XXXXXXX 100755
219
--- a/tests/qemu-iotests/151
220
+++ b/tests/qemu-iotests/151
221
@@ -XXX,XX +XXX,XX @@ class TestActiveMirror(iotests.QMPTestCase):
222
223
224
if __name__ == '__main__':
225
- iotests.main(supported_fmts=['qcow2', 'raw'])
226
+ iotests.main(supported_fmts=['qcow2', 'raw'],
227
+ supported_protocols=['file'])
228
diff --git a/tests/qemu-iotests/152 b/tests/qemu-iotests/152
229
index XXXXXXX..XXXXXXX 100755
230
--- a/tests/qemu-iotests/152
231
+++ b/tests/qemu-iotests/152
232
@@ -XXX,XX +XXX,XX @@ class TestUnaligned(iotests.QMPTestCase):
233
234
235
if __name__ == '__main__':
236
- iotests.main(supported_fmts=['raw', 'qcow2'])
237
+ iotests.main(supported_fmts=['raw', 'qcow2'],
238
+ supported_protocols=['file'])
239
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
240
index XXXXXXX..XXXXXXX 100755
241
--- a/tests/qemu-iotests/155
242
+++ b/tests/qemu-iotests/155
243
@@ -XXX,XX +XXX,XX @@ BaseClass = None
244
MirrorBaseClass = None
245
246
if __name__ == '__main__':
247
- iotests.main(supported_fmts=['qcow2'])
248
+ iotests.main(supported_fmts=['qcow2'],
249
+ supported_protocols=['file'])
250
diff --git a/tests/qemu-iotests/163 b/tests/qemu-iotests/163
251
index XXXXXXX..XXXXXXX 100755
252
--- a/tests/qemu-iotests/163
253
+++ b/tests/qemu-iotests/163
254
@@ -XXX,XX +XXX,XX @@ class TestShrink1M(ShrinkBaseClass):
255
ShrinkBaseClass = None
256
257
if __name__ == '__main__':
258
- iotests.main(supported_fmts=['raw', 'qcow2'])
259
+ iotests.main(supported_fmts=['raw', 'qcow2'],
260
+ supported_protocols=['file'])
261
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
262
index XXXXXXX..XXXXXXX 100755
263
--- a/tests/qemu-iotests/165
264
+++ b/tests/qemu-iotests/165
265
@@ -XXX,XX +XXX,XX @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
266
self.vm.shutdown()
267
268
if __name__ == '__main__':
269
- iotests.main(supported_fmts=['qcow2'])
270
+ iotests.main(supported_fmts=['qcow2'],
271
+ supported_protocols=['file'])
272
diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169
273
index XXXXXXX..XXXXXXX 100755
274
--- a/tests/qemu-iotests/169
275
+++ b/tests/qemu-iotests/169
276
@@ -XXX,XX +XXX,XX @@ for cmb in list(itertools.product((True, False), repeat=2)):
277
'do_test_migration_resume_source', *list(cmb))
278
279
if __name__ == '__main__':
280
- iotests.main(supported_fmts=['qcow2'])
281
+ iotests.main(supported_fmts=['qcow2'],
282
+ supported_protocols=['file'])
283
diff --git a/tests/qemu-iotests/196 b/tests/qemu-iotests/196
284
index XXXXXXX..XXXXXXX 100755
285
--- a/tests/qemu-iotests/196
286
+++ b/tests/qemu-iotests/196
287
@@ -XXX,XX +XXX,XX @@ class TestInvalidateAutoclear(iotests.QMPTestCase):
288
self.assertEqual(f.read(1), b'\x00')
289
290
if __name__ == '__main__':
291
- iotests.main(supported_fmts=['qcow2'])
292
+ iotests.main(supported_fmts=['qcow2'],
293
+ supported_protocols=['file'])
294
diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199
295
index XXXXXXX..XXXXXXX 100755
296
--- a/tests/qemu-iotests/199
297
+++ b/tests/qemu-iotests/199
298
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
299
self.assert_qmp(result, 'return/sha256', sha256);
300
301
if __name__ == '__main__':
302
- iotests.main(supported_fmts=['qcow2'], supported_cache_modes=['none'])
303
+ iotests.main(supported_fmts=['qcow2'], supported_cache_modes=['none'],
304
+ supported_protocols=['file'])
305
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
306
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
307
--- a/tests/qemu-iotests/245
14
--- a/block/io.c
308
+++ b/tests/qemu-iotests/245
15
+++ b/block/io.c
309
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
16
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
310
self.reopen(opts, {'backing': 'hd2'})
17
311
18
void bdrv_drained_end(BlockDriverState *bs)
312
if __name__ == '__main__':
19
{
313
- iotests.main(supported_fmts=["qcow2"])
20
+ int old_quiesce_counter;
314
+ iotests.main(supported_fmts=["qcow2"],
21
+
315
+ supported_protocols=["file"])
22
if (qemu_in_coroutine()) {
316
diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
23
bdrv_co_yield_to_drain(bs, false);
317
index XXXXXXX..XXXXXXX 100755
24
return;
318
--- a/tests/qemu-iotests/257
25
}
319
+++ b/tests/qemu-iotests/257
26
assert(bs->quiesce_counter > 0);
320
@@ -XXX,XX +XXX,XX @@ def main():
27
- if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
321
test_backup_api()
28
- return;
322
29
- }
323
if __name__ == '__main__':
30
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
324
- iotests.script_main(main, supported_fmts=['qcow2'])
31
325
+ iotests.script_main(main, supported_fmts=['qcow2'],
32
/* Re-enable things in child-to-parent order */
326
+ supported_protocols=['file'])
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
/*
327
--
43
--
328
2.20.1
44
2.13.6
329
45
330
46
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
2
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
2
---
6
tests/qemu-iotests/iotests.py | 4 +++-
3
tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
7
1 file changed, 3 insertions(+), 1 deletion(-)
4
1 file changed, 57 insertions(+)
8
5
9
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
10
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/qemu-iotests/iotests.py
8
--- a/tests/test-bdrv-drain.c
12
+++ b/tests/qemu-iotests/iotests.py
9
+++ b/tests/test-bdrv-drain.c
13
@@ -XXX,XX +XXX,XX @@ def execute_unittest(output, verbosity, debug):
10
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
14
11
enum drain_type {
15
def execute_test(test_function=None,
12
BDRV_DRAIN_ALL,
16
supported_fmts=[], supported_oses=['linux'],
13
BDRV_DRAIN,
17
- supported_cache_modes=[], unsupported_fmts=[]):
14
+ DRAIN_TYPE_MAX,
18
+ supported_cache_modes=[], unsupported_fmts=[],
15
};
19
+ supported_protocols=[], unsupported_protocols=[]):
16
20
"""Run either unittest or script-style tests."""
17
static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
21
18
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
22
# We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to
19
test_quiesce_common(BDRV_DRAIN, false);
23
@@ -XXX,XX +XXX,XX @@ def execute_test(test_function=None,
20
}
24
debug = '-d' in sys.argv
21
25
verbosity = 1
22
+static void test_nested(void)
26
verify_image_format(supported_fmts, unsupported_fmts)
23
+{
27
+ verify_protocol(supported_protocols, unsupported_protocols)
24
+ BlockBackend *blk;
28
verify_platform(supported_oses)
25
+ BlockDriverState *bs, *backing;
29
verify_cache_mode(supported_cache_modes)
26
+ BDRVTestState *s, *backing_s;
27
+ enum drain_type outer, inner;
28
+
29
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
30
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
31
+ &error_abort);
32
+ s = bs->opaque;
33
+ blk_insert_bs(blk, bs, &error_abort);
34
+
35
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
36
+ backing_s = backing->opaque;
37
+ bdrv_set_backing_hd(bs, backing, &error_abort);
38
+
39
+ for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
40
+ for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
41
+ /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
42
+ int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
43
+ (inner != BDRV_DRAIN_ALL);
44
+ int backing_quiesce = 0;
45
+ int backing_cb_cnt = (outer != BDRV_DRAIN) +
46
+ (inner != BDRV_DRAIN);
47
+
48
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
49
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
50
+ g_assert_cmpint(s->drain_count, ==, 0);
51
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
52
+
53
+ do_drain_begin(outer, bs);
54
+ do_drain_begin(inner, bs);
55
+
56
+ g_assert_cmpint(bs->quiesce_counter, ==, bs_quiesce);
57
+ g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce);
58
+ g_assert_cmpint(s->drain_count, ==, 2);
59
+ g_assert_cmpint(backing_s->drain_count, ==, backing_cb_cnt);
60
+
61
+ do_drain_end(inner, bs);
62
+ do_drain_end(outer, bs);
63
+
64
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
65
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
66
+ g_assert_cmpint(s->drain_count, ==, 0);
67
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
68
+ }
69
+ }
70
+
71
+ bdrv_unref(backing);
72
+ bdrv_unref(bs);
73
+ blk_unref(blk);
74
+}
75
+
76
77
typedef struct TestBlockJob {
78
BlockJob common;
79
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
80
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
81
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
82
83
+ g_test_add_func("/bdrv-drain/nested", test_nested);
84
+
85
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
86
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
30
87
31
--
88
--
32
2.20.1
89
2.13.6
33
90
34
91
diff view generated by jsdifflib
New patch
1
1
This is in preparation for subtree drains, i.e. drained sections that
2
affect not only a single node, but recursively all child nodes, too.
3
4
Calling the parent callbacks for drain is pointless when we just came
5
from that parent node recursively and leads to multiple increases of
6
bs->quiesce_counter in a single drain call. Don't do it.
7
8
In order for this to work correctly, the parent callback must be called
9
for every bdrv_drain_begin/end() call, not only for the outermost one:
10
11
If we have a node N with two parents A and B, recursive draining of A
12
should cause the quiesce_counter of B to increase because its child N is
13
drained independently of B. If now B is recursively drained, too, A must
14
increase its quiesce_counter because N is drained independently of A
15
only now, even if N is going from quiesce_counter 1 to 2.
16
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
include/block/block.h | 4 ++--
20
block.c | 13 +++++++++----
21
block/io.c | 47 ++++++++++++++++++++++++++++++++++-------------
22
3 files changed, 45 insertions(+), 19 deletions(-)
23
24
diff --git a/include/block/block.h b/include/block/block.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/block/block.h
27
+++ b/include/block/block.h
28
@@ -XXX,XX +XXX,XX @@ void bdrv_io_unplug(BlockDriverState *bs);
29
* Begin a quiesced section of all users of @bs. This is part of
30
* bdrv_drained_begin.
31
*/
32
-void bdrv_parent_drained_begin(BlockDriverState *bs);
33
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore);
34
35
/**
36
* bdrv_parent_drained_end:
37
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin(BlockDriverState *bs);
38
* End a quiesced section of all users of @bs. This is part of
39
* bdrv_drained_end.
40
*/
41
-void bdrv_parent_drained_end(BlockDriverState *bs);
42
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
43
44
/**
45
* bdrv_drained_begin:
46
diff --git a/block.c b/block.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block.c
49
+++ b/block.c
50
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
51
BlockDriverState *new_bs)
52
{
53
BlockDriverState *old_bs = child->bs;
54
+ int i;
55
56
if (old_bs && new_bs) {
57
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
58
}
59
if (old_bs) {
60
if (old_bs->quiesce_counter && child->role->drained_end) {
61
- child->role->drained_end(child);
62
+ for (i = 0; i < old_bs->quiesce_counter; i++) {
63
+ child->role->drained_end(child);
64
+ }
65
}
66
if (child->role->detach) {
67
child->role->detach(child);
68
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
69
if (new_bs) {
70
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
71
if (new_bs->quiesce_counter && child->role->drained_begin) {
72
- child->role->drained_begin(child);
73
+ for (i = 0; i < new_bs->quiesce_counter; i++) {
74
+ child->role->drained_begin(child);
75
+ }
76
}
77
78
if (child->role->attach) {
79
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
80
AioContext *ctx = bdrv_get_aio_context(bs);
81
82
aio_disable_external(ctx);
83
- bdrv_parent_drained_begin(bs);
84
+ bdrv_parent_drained_begin(bs, NULL);
85
bdrv_drain(bs); /* ensure there are no in-flight requests */
86
87
while (aio_poll(ctx, false)) {
88
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
89
*/
90
aio_context_acquire(new_context);
91
bdrv_attach_aio_context(bs, new_context);
92
- bdrv_parent_drained_end(bs);
93
+ bdrv_parent_drained_end(bs, NULL);
94
aio_enable_external(ctx);
95
aio_context_release(new_context);
96
}
97
diff --git a/block/io.c b/block/io.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/io.c
100
+++ b/block/io.c
101
@@ -XXX,XX +XXX,XX @@
102
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
103
int64_t offset, int bytes, BdrvRequestFlags flags);
104
105
-void bdrv_parent_drained_begin(BlockDriverState *bs)
106
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
107
{
108
BdrvChild *c, *next;
109
110
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
111
+ if (c == ignore) {
112
+ continue;
113
+ }
114
if (c->role->drained_begin) {
115
c->role->drained_begin(c);
116
}
117
}
118
}
119
120
-void bdrv_parent_drained_end(BlockDriverState *bs)
121
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
122
{
123
BdrvChild *c, *next;
124
125
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
126
+ if (c == ignore) {
127
+ continue;
128
+ }
129
if (c->role->drained_end) {
130
c->role->drained_end(c);
131
}
132
@@ -XXX,XX +XXX,XX @@ typedef struct {
133
BlockDriverState *bs;
134
bool done;
135
bool begin;
136
+ BdrvChild *parent;
137
} BdrvCoDrainData;
138
139
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
140
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
141
return waited;
142
}
143
144
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
145
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
146
+
147
static void bdrv_co_drain_bh_cb(void *opaque)
148
{
149
BdrvCoDrainData *data = opaque;
150
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
151
152
bdrv_dec_in_flight(bs);
153
if (data->begin) {
154
- bdrv_drained_begin(bs);
155
+ bdrv_do_drained_begin(bs, data->parent);
156
} else {
157
- bdrv_drained_end(bs);
158
+ bdrv_do_drained_end(bs, data->parent);
159
}
160
161
data->done = true;
162
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
163
}
164
165
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
166
- bool begin)
167
+ bool begin, BdrvChild *parent)
168
{
169
BdrvCoDrainData data;
170
171
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
172
.bs = bs,
173
.done = false,
174
.begin = begin,
175
+ .parent = parent,
176
};
177
bdrv_inc_in_flight(bs);
178
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
179
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
180
assert(data.done);
181
}
182
183
-void bdrv_drained_begin(BlockDriverState *bs)
184
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
185
{
186
if (qemu_in_coroutine()) {
187
- bdrv_co_yield_to_drain(bs, true);
188
+ bdrv_co_yield_to_drain(bs, true, parent);
189
return;
190
}
191
192
/* Stop things in parent-to-child order */
193
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
194
aio_disable_external(bdrv_get_aio_context(bs));
195
- bdrv_parent_drained_begin(bs);
196
}
197
198
+ bdrv_parent_drained_begin(bs, parent);
199
bdrv_drain_invoke(bs, true, false);
200
bdrv_drain_recurse(bs);
201
}
202
203
-void bdrv_drained_end(BlockDriverState *bs)
204
+void bdrv_drained_begin(BlockDriverState *bs)
205
+{
206
+ bdrv_do_drained_begin(bs, NULL);
207
+}
208
+
209
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
210
{
211
int old_quiesce_counter;
212
213
if (qemu_in_coroutine()) {
214
- bdrv_co_yield_to_drain(bs, false);
215
+ bdrv_co_yield_to_drain(bs, false, parent);
216
return;
217
}
218
assert(bs->quiesce_counter > 0);
219
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
220
221
/* Re-enable things in child-to-parent order */
222
bdrv_drain_invoke(bs, false, false);
223
+ bdrv_parent_drained_end(bs, parent);
224
if (old_quiesce_counter == 1) {
225
- bdrv_parent_drained_end(bs);
226
aio_enable_external(bdrv_get_aio_context(bs));
227
}
228
}
229
230
+void bdrv_drained_end(BlockDriverState *bs)
231
+{
232
+ bdrv_do_drained_end(bs, NULL);
233
+}
234
+
235
/*
236
* Wait for pending requests to complete on a single BlockDriverState subtree,
237
* and suspend block driver's internal I/O until next request arrives.
238
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
239
/* Stop things in parent-to-child order */
240
aio_context_acquire(aio_context);
241
aio_disable_external(aio_context);
242
- bdrv_parent_drained_begin(bs);
243
+ bdrv_parent_drained_begin(bs, NULL);
244
bdrv_drain_invoke(bs, true, true);
245
aio_context_release(aio_context);
246
247
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
248
/* Re-enable things in child-to-parent order */
249
aio_context_acquire(aio_context);
250
bdrv_drain_invoke(bs, false, true);
251
- bdrv_parent_drained_end(bs);
252
+ bdrv_parent_drained_end(bs, NULL);
253
aio_enable_external(aio_context);
254
aio_context_release(aio_context);
255
}
256
--
257
2.13.6
258
259
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.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
blockdev_create_run() directly uses .bdrv_co_create()'s return value as
5
Add a version that keeps the whole subtree drained. As of this commit,
4
the job's return value. Jobs must return 0 on success, not just any
6
graph changes cannot be allowed during a subtree drained section, but
5
nonnegative value. Therefore, using blockdev-create for VPC images may
7
this will be fixed soon.
6
currently fail as the vpc driver may return a positive integer.
7
8
8
Because there is no point in returning a positive integer anywhere in
9
the block layer (all non-negative integers are generally treated as
10
complete success), we probably do not want to add more such cases.
11
Therefore, fix this problem by making the vpc driver always return 0 in
12
case of success.
13
14
Suggested-by: Kevin Wolf <kwolf@redhat.com>
15
Cc: qemu-stable@nongnu.org
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
10
---
19
block/vpc.c | 3 ++-
11
include/block/block.h | 13 +++++++++++++
20
1 file changed, 2 insertions(+), 1 deletion(-)
12
block/io.c | 54 ++++++++++++++++++++++++++++++++++++++++-----------
13
2 files changed, 56 insertions(+), 11 deletions(-)
21
14
22
diff --git a/block/vpc.c b/block/vpc.c
15
diff --git a/include/block/block.h b/include/block/block.h
23
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
24
--- a/block/vpc.c
17
--- a/include/block/block.h
25
+++ b/block/vpc.c
18
+++ b/include/block/block.h
26
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
19
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
27
goto fail;
20
void bdrv_drained_begin(BlockDriverState *bs);
21
22
/**
23
+ * Like bdrv_drained_begin, but recursively begins a quiesced section for
24
+ * exclusive access to all child nodes as well.
25
+ *
26
+ * Graph changes are not allowed during a subtree drain section.
27
+ */
28
+void bdrv_subtree_drained_begin(BlockDriverState *bs);
29
+
30
+/**
31
* bdrv_drained_end:
32
*
33
* End a quiescent section started by bdrv_drained_begin().
34
*/
35
void bdrv_drained_end(BlockDriverState *bs);
36
37
+/**
38
+ * End a quiescent section started by bdrv_subtree_drained_begin().
39
+ */
40
+void bdrv_subtree_drained_end(BlockDriverState *bs);
41
+
42
void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
43
Error **errp);
44
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
45
diff --git a/block/io.c b/block/io.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block/io.c
48
+++ b/block/io.c
49
@@ -XXX,XX +XXX,XX @@ typedef struct {
50
BlockDriverState *bs;
51
bool done;
52
bool begin;
53
+ bool recursive;
54
BdrvChild *parent;
55
} BdrvCoDrainData;
56
57
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
58
return waited;
59
}
60
61
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
62
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
63
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
64
+ BdrvChild *parent);
65
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
66
+ BdrvChild *parent);
67
68
static void bdrv_co_drain_bh_cb(void *opaque)
69
{
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
71
72
bdrv_dec_in_flight(bs);
73
if (data->begin) {
74
- bdrv_do_drained_begin(bs, data->parent);
75
+ bdrv_do_drained_begin(bs, data->recursive, data->parent);
76
} else {
77
- bdrv_do_drained_end(bs, data->parent);
78
+ bdrv_do_drained_end(bs, data->recursive, data->parent);
28
}
79
}
29
80
30
+ ret = 0;
81
data->done = true;
31
fail:
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
32
return ret;
33
}
83
}
34
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
84
35
return ret;
85
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
86
- bool begin, BdrvChild *parent)
87
+ bool begin, bool recursive,
88
+ BdrvChild *parent)
89
{
90
BdrvCoDrainData data;
91
92
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
93
.bs = bs,
94
.done = false,
95
.begin = begin,
96
+ .recursive = recursive,
97
.parent = parent,
98
};
99
bdrv_inc_in_flight(bs);
100
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
101
assert(data.done);
102
}
103
104
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
105
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
106
+ BdrvChild *parent)
107
{
108
+ BdrvChild *child, *next;
109
+
110
if (qemu_in_coroutine()) {
111
- bdrv_co_yield_to_drain(bs, true, parent);
112
+ bdrv_co_yield_to_drain(bs, true, recursive, parent);
113
return;
36
}
114
}
37
115
38
- return ret;
116
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
39
+ return 0;
117
bdrv_parent_drained_begin(bs, parent);
118
bdrv_drain_invoke(bs, true, false);
119
bdrv_drain_recurse(bs);
120
+
121
+ if (recursive) {
122
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
123
+ bdrv_do_drained_begin(child->bs, true, child);
124
+ }
125
+ }
40
}
126
}
41
127
42
static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts,
128
void bdrv_drained_begin(BlockDriverState *bs)
129
{
130
- bdrv_do_drained_begin(bs, NULL);
131
+ bdrv_do_drained_begin(bs, false, NULL);
132
+}
133
+
134
+void bdrv_subtree_drained_begin(BlockDriverState *bs)
135
+{
136
+ bdrv_do_drained_begin(bs, true, NULL);
137
}
138
139
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
140
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
141
+ BdrvChild *parent)
142
{
143
+ BdrvChild *child, *next;
144
int old_quiesce_counter;
145
146
if (qemu_in_coroutine()) {
147
- bdrv_co_yield_to_drain(bs, false, parent);
148
+ bdrv_co_yield_to_drain(bs, false, recursive, parent);
149
return;
150
}
151
assert(bs->quiesce_counter > 0);
152
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
153
if (old_quiesce_counter == 1) {
154
aio_enable_external(bdrv_get_aio_context(bs));
155
}
156
+
157
+ if (recursive) {
158
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
159
+ bdrv_do_drained_end(child->bs, true, child);
160
+ }
161
+ }
162
}
163
164
void bdrv_drained_end(BlockDriverState *bs)
165
{
166
- bdrv_do_drained_end(bs, NULL);
167
+ bdrv_do_drained_end(bs, false, NULL);
168
+}
169
+
170
+void bdrv_subtree_drained_end(BlockDriverState *bs)
171
+{
172
+ bdrv_do_drained_end(bs, true, NULL);
173
}
174
175
/*
43
--
176
--
44
2.20.1
177
2.13.6
45
178
46
179
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
Add a subtree drain version to the existing test cases.
2
2
3
With the '-valgrind' option, let all the QEMU processes be run under
4
the Valgrind tool. The Valgrind own parameters may be set with its
5
environment variable VALGRIND_OPTS, e.g.
6
$ VALGRIND_OPTS="--leak-check=yes" ./check -valgrind <test#>
7
or they may be listed in the Valgrind checked file ./.valgrindrc or
8
~/.valgrindrc like
9
--memcheck:leak-check=no
10
--memcheck:track-origins=yes
11
To exclude a specific process from running under the Valgrind, the
12
corresponding environment variable VALGRIND_QEMU_<name> is to be set
13
to the empty string:
14
$ VALGRIND_QEMU_IO= ./check -valgrind <test#>
15
When QEMU-IO process is being killed, the shell report refers to the
16
text of the command in _qemu_io_wrapper(), which was modified with this
17
patch. So, the benchmark output for the tests 039, 061 and 137 is to be
18
changed also.
19
20
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
4
---
23
tests/qemu-iotests/039.out | 30 ++----------
5
tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++-
24
tests/qemu-iotests/061.out | 12 +----
6
1 file changed, 26 insertions(+), 1 deletion(-)
25
tests/qemu-iotests/137.out | 6 +--
26
tests/qemu-iotests/common.rc | 88 ++++++++++++++++++++++++++++--------
27
4 files changed, 78 insertions(+), 58 deletions(-)
28
7
29
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
30
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
31
--- a/tests/qemu-iotests/039.out
10
--- a/tests/test-bdrv-drain.c
32
+++ b/tests/qemu-iotests/039.out
11
+++ b/tests/test-bdrv-drain.c
33
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
12
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
34
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
13
enum drain_type {
35
wrote 512/512 bytes at offset 0
14
BDRV_DRAIN_ALL,
36
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
15
BDRV_DRAIN,
37
-./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
16
+ BDRV_SUBTREE_DRAIN,
38
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
17
DRAIN_TYPE_MAX,
39
-else
18
};
40
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
19
41
-fi )
20
@@ -XXX,XX +XXX,XX @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
42
+./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
21
switch (drain_type) {
43
incompatible_features 0x1
22
case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
44
ERROR cluster 5 refcount=0 reference=1
23
case BDRV_DRAIN: bdrv_drained_begin(bs); break;
45
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
24
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break;
46
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0
25
default: g_assert_not_reached();
47
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
26
}
48
wrote 512/512 bytes at offset 0
27
}
49
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
28
@@ -XXX,XX +XXX,XX @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
50
-./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
29
switch (drain_type) {
51
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
30
case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
52
-else
31
case BDRV_DRAIN: bdrv_drained_end(bs); break;
53
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
32
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break;
54
-fi )
33
default: g_assert_not_reached();
55
+./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
34
}
56
incompatible_features 0x1
35
}
57
ERROR cluster 5 refcount=0 reference=1
36
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
58
Rebuilding refcount structure
37
test_drv_cb_common(BDRV_DRAIN, false);
59
@@ -XXX,XX +XXX,XX @@ incompatible_features 0x0
38
}
60
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
39
61
wrote 512/512 bytes at offset 0
40
+static void test_drv_cb_drain_subtree(void)
62
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
63
-./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
64
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
65
-else
66
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
67
-fi )
68
+./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
69
incompatible_features 0x0
70
No errors were found on the image.
71
72
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
73
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
74
wrote 512/512 bytes at offset 0
75
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76
-./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
77
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
78
-else
79
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
80
-fi )
81
+./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
82
incompatible_features 0x1
83
ERROR cluster 5 refcount=0 reference=1
84
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
85
@@ -XXX,XX +XXX,XX @@ Data may be corrupted, or further writes to the image may corrupt it.
86
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
87
wrote 512/512 bytes at offset 0
88
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
89
-./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
90
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
91
-else
92
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
93
-fi )
94
+./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
95
incompatible_features 0x0
96
No errors were found on the image.
97
*** done
98
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
99
index XXXXXXX..XXXXXXX 100644
100
--- a/tests/qemu-iotests/061.out
101
+++ b/tests/qemu-iotests/061.out
102
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
103
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
104
wrote 131072/131072 bytes at offset 0
105
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
106
-./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
107
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
108
-else
109
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
110
-fi )
111
+./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
112
magic 0x514649fb
113
version 3
114
backing_file_offset 0x0
115
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
116
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
117
wrote 131072/131072 bytes at offset 0
118
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
119
-./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
120
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
121
-else
122
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
123
-fi )
124
+./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
125
magic 0x514649fb
126
version 3
127
backing_file_offset 0x0
128
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
129
index XXXXXXX..XXXXXXX 100644
130
--- a/tests/qemu-iotests/137.out
131
+++ b/tests/qemu-iotests/137.out
132
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
133
qemu-io: Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
134
wrote 512/512 bytes at offset 0
135
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
136
-./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
137
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
138
-else
139
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
140
-fi )
141
+./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
142
incompatible_features 0x0
143
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
144
wrote 65536/65536 bytes at offset 0
145
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
146
index XXXXXXX..XXXXXXX 100644
147
--- a/tests/qemu-iotests/common.rc
148
+++ b/tests/qemu-iotests/common.rc
149
@@ -XXX,XX +XXX,XX @@ if ! . ./common.config
150
exit 1
151
fi
152
153
+# Set the variables to the empty string to turn Valgrind off
154
+# for specific processes, e.g.
155
+# $ VALGRIND_QEMU_IO= ./check -qcow2 -valgrind 015
156
+
157
+: ${VALGRIND_QEMU_VM=$VALGRIND_QEMU}
158
+: ${VALGRIND_QEMU_IMG=$VALGRIND_QEMU}
159
+: ${VALGRIND_QEMU_IO=$VALGRIND_QEMU}
160
+: ${VALGRIND_QEMU_NBD=$VALGRIND_QEMU}
161
+: ${VALGRIND_QEMU_VXHS=$VALGRIND_QEMU}
162
+
163
+# The Valgrind own parameters may be set with
164
+# its environment variable VALGRIND_OPTS, e.g.
165
+# $ VALGRIND_OPTS="--leak-check=yes" ./check -qcow2 -valgrind 015
166
+
167
+_qemu_proc_exec()
168
+{
41
+{
169
+ local VALGRIND_LOGFILE="$1"
42
+ test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
170
+ shift
171
+ if [ "${VALGRIND_QEMU}" == "y" ]; then
172
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$@"
173
+ else
174
+ exec "$@"
175
+ fi
176
+}
43
+}
177
+
44
+
178
+_qemu_proc_valgrind_log()
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)
179
+{
53
+{
180
+ local VALGRIND_LOGFILE="$1"
54
+ test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
181
+ local RETVAL="$2"
182
+ if [ "${VALGRIND_QEMU}" == "y" ]; then
183
+ if [ $RETVAL == 99 ]; then
184
+ cat "${VALGRIND_LOGFILE}"
185
+ fi
186
+ rm -f "${VALGRIND_LOGFILE}"
187
+ fi
188
+}
55
+}
189
+
56
+
190
_qemu_wrapper()
57
static void test_nested(void)
191
{
58
{
192
+ local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
59
BlockBackend *blk;
193
(
60
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
194
if [ -n "${QEMU_NEED_PID}" ]; then
61
/* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
195
echo $BASHPID > "${QEMU_TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
62
int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
196
fi
63
(inner != BDRV_DRAIN_ALL);
197
- exec "$QEMU_PROG" $QEMU_OPTIONS "$@"
64
- int backing_quiesce = 0;
198
+ VALGRIND_QEMU="${VALGRIND_QEMU_VM}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
65
+ int backing_quiesce = (outer == BDRV_SUBTREE_DRAIN) +
199
+ "$QEMU_PROG" $QEMU_OPTIONS "$@"
66
+ (inner == BDRV_SUBTREE_DRAIN);
200
)
67
int backing_cb_cnt = (outer != BDRV_DRAIN) +
201
+ RETVAL=$?
68
(inner != BDRV_DRAIN);
202
+ _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
69
203
+ return $RETVAL
70
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_drain(void)
71
test_blockjob_common(BDRV_DRAIN);
204
}
72
}
205
73
206
_qemu_img_wrapper()
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)
207
{
80
{
208
- (exec "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@")
81
bdrv_init();
209
+ local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
82
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
210
+ (
83
211
+ VALGRIND_QEMU="${VALGRIND_QEMU_IMG}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
84
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
212
+ "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@"
85
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
213
+ )
86
+ g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
214
+ RETVAL=$?
87
+ test_drv_cb_drain_subtree);
215
+ _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
88
216
+ return $RETVAL
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();
217
}
102
}
218
219
_qemu_io_wrapper()
220
@@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper()
221
QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
222
fi
223
fi
224
- local RETVAL
225
(
226
- if [ "${VALGRIND_QEMU}" == "y" ]; then
227
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
228
- else
229
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
230
- fi
231
+ VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
232
+ "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
233
)
234
RETVAL=$?
235
- if [ "${VALGRIND_QEMU}" == "y" ]; then
236
- if [ $RETVAL == 99 ]; then
237
- cat "${VALGRIND_LOGFILE}"
238
- fi
239
- rm -f "${VALGRIND_LOGFILE}"
240
- fi
241
- (exit $RETVAL)
242
+ _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
243
+ return $RETVAL
244
}
245
246
_qemu_nbd_wrapper()
247
{
248
- "$QEMU_NBD_PROG" --pid-file="${QEMU_TEST_DIR}/qemu-nbd.pid" \
249
- $QEMU_NBD_OPTIONS "$@"
250
+ local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
251
+ (
252
+ VALGRIND_QEMU="${VALGRIND_QEMU_NBD}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
253
+ "$QEMU_NBD_PROG" --pid-file="${QEMU_TEST_DIR}/qemu-nbd.pid" \
254
+ $QEMU_NBD_OPTIONS "$@"
255
+ )
256
+ RETVAL=$?
257
+ _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
258
+ return $RETVAL
259
}
260
261
_qemu_vxhs_wrapper()
262
{
263
+ local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
264
(
265
echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
266
- exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
267
+ VALGRIND_QEMU="${VALGRIND_QEMU_VXHS}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
268
+ "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
269
)
270
+ RETVAL=$?
271
+ _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
272
+ return $RETVAL
273
}
274
275
export QEMU=_qemu_wrapper
276
--
103
--
277
2.20.1
104
2.13.6
278
105
279
106
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.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
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
---
6
tests/qemu-iotests/266 | 153 +++++++++++++++++++++++++++++++++++++
7
tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
7
tests/qemu-iotests/266.out | 137 +++++++++++++++++++++++++++++++++
8
1 file changed, 59 insertions(+)
8
tests/qemu-iotests/group | 1 +
9
3 files changed, 291 insertions(+)
10
create mode 100755 tests/qemu-iotests/266
11
create mode 100644 tests/qemu-iotests/266.out
12
9
13
diff --git a/tests/qemu-iotests/266 b/tests/qemu-iotests/266
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
new file mode 100755
11
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX
12
--- a/tests/test-bdrv-drain.c
16
--- /dev/null
13
+++ b/tests/test-bdrv-drain.c
17
+++ b/tests/qemu-iotests/266
14
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
18
@@ -XXX,XX +XXX,XX @@
15
*aio_ret = ret;
19
+#!/usr/bin/env python
16
}
20
+#
17
21
+# Test VPC and file image creation
18
+typedef struct CallInCoroutineData {
22
+#
19
+ void (*entry)(void);
23
+# Copyright (C) 2019 Red Hat, Inc.
20
+ bool done;
24
+#
21
+} CallInCoroutineData;
25
+# This program is free software; you can redistribute it and/or modify
26
+# it under the terms of the GNU General Public License as published by
27
+# the Free Software Foundation; either version 2 of the License, or
28
+# (at your option) any later version.
29
+#
30
+# This program is distributed in the hope that it will be useful,
31
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
32
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33
+# GNU General Public License for more details.
34
+#
35
+# You should have received a copy of the GNU General Public License
36
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
37
+#
38
+
22
+
39
+import iotests
23
+static coroutine_fn void call_in_coroutine_entry(void *opaque)
40
+from iotests import imgfmt
24
+{
25
+ CallInCoroutineData *data = opaque;
26
+
27
+ data->entry();
28
+ data->done = true;
29
+}
30
+
31
+static void call_in_coroutine(void (*entry)(void))
32
+{
33
+ Coroutine *co;
34
+ CallInCoroutineData data = {
35
+ .entry = entry,
36
+ .done = false,
37
+ };
38
+
39
+ co = qemu_coroutine_create(call_in_coroutine_entry, &data);
40
+ qemu_coroutine_enter(co);
41
+ while (!data.done) {
42
+ aio_poll(qemu_get_aio_context(), true);
43
+ }
44
+}
45
+
46
enum drain_type {
47
BDRV_DRAIN_ALL,
48
BDRV_DRAIN,
49
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_subtree(void)
50
test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
51
}
52
53
+static void test_drv_cb_co_drain(void)
54
+{
55
+ call_in_coroutine(test_drv_cb_drain);
56
+}
57
+
58
+static void test_drv_cb_co_drain_subtree(void)
59
+{
60
+ call_in_coroutine(test_drv_cb_drain_subtree);
61
+}
62
+
63
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
64
{
65
BlockBackend *blk;
66
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain_subtree(void)
67
test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
68
}
69
70
+static void test_quiesce_co_drain(void)
71
+{
72
+ call_in_coroutine(test_quiesce_drain);
73
+}
74
+
75
+static void test_quiesce_co_drain_subtree(void)
76
+{
77
+ call_in_coroutine(test_quiesce_drain_subtree);
78
+}
79
+
80
static void test_nested(void)
81
{
82
BlockBackend *blk;
83
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
84
g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
85
test_drv_cb_drain_subtree);
86
87
+ // XXX bdrv_drain_all() doesn't work in coroutine context
88
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain);
89
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree",
90
+ test_drv_cb_co_drain_subtree);
41
+
91
+
42
+
92
+
43
+def blockdev_create(vm, options):
93
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
44
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
94
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
45
+ filters=[iotests.filter_qmp_testfiles])
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);
46
+
102
+
47
+ if 'return' in result:
103
g_test_add_func("/bdrv-drain/nested", test_nested);
48
+ assert result['return'] == {}
104
49
+ vm.run_job('job0')
105
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
50
+
51
+
52
+# Successful image creation (defaults)
53
+def implicit_defaults(vm, file_path):
54
+ iotests.log("=== Successful image creation (defaults) ===")
55
+ iotests.log("")
56
+
57
+ # 8 heads, 964 cyls/head, 17 secs/cyl
58
+ # (Close to 64 MB)
59
+ size = 8 * 964 * 17 * 512
60
+
61
+ blockdev_create(vm, { 'driver': imgfmt,
62
+ 'file': 'protocol-node',
63
+ 'size': size })
64
+
65
+
66
+# Successful image creation (explicit defaults)
67
+def explicit_defaults(vm, file_path):
68
+ iotests.log("=== Successful image creation (explicit defaults) ===")
69
+ iotests.log("")
70
+
71
+ # 16 heads, 964 cyls/head, 17 secs/cyl
72
+ # (Close to 128 MB)
73
+ size = 16 * 964 * 17 * 512
74
+
75
+ blockdev_create(vm, { 'driver': imgfmt,
76
+ 'file': 'protocol-node',
77
+ 'size': size,
78
+ 'subformat': 'dynamic',
79
+ 'force-size': False })
80
+
81
+
82
+# Successful image creation (non-default options)
83
+def non_defaults(vm, file_path):
84
+ iotests.log("=== Successful image creation (non-default options) ===")
85
+ iotests.log("")
86
+
87
+ # Not representable in CHS (fine with force-size=True)
88
+ size = 1048576
89
+
90
+ blockdev_create(vm, { 'driver': imgfmt,
91
+ 'file': 'protocol-node',
92
+ 'size': size,
93
+ 'subformat': 'fixed',
94
+ 'force-size': True })
95
+
96
+
97
+# Size not representable in CHS with force-size=False
98
+def non_chs_size_without_force(vm, file_path):
99
+ iotests.log("=== Size not representable in CHS ===")
100
+ iotests.log("")
101
+
102
+ # Not representable in CHS (will not work with force-size=False)
103
+ size = 1048576
104
+
105
+ blockdev_create(vm, { 'driver': imgfmt,
106
+ 'file': 'protocol-node',
107
+ 'size': size,
108
+ 'force-size': False })
109
+
110
+
111
+# Zero size
112
+def zero_size(vm, file_path):
113
+ iotests.log("=== Zero size===")
114
+ iotests.log("")
115
+
116
+ blockdev_create(vm, { 'driver': imgfmt,
117
+ 'file': 'protocol-node',
118
+ 'size': 0 })
119
+
120
+
121
+# Maximum CHS size
122
+def maximum_chs_size(vm, file_path):
123
+ iotests.log("=== Maximum CHS size===")
124
+ iotests.log("")
125
+
126
+ blockdev_create(vm, { 'driver': imgfmt,
127
+ 'file': 'protocol-node',
128
+ 'size': 16 * 65535 * 255 * 512 })
129
+
130
+
131
+# Actual maximum size
132
+def maximum_size(vm, file_path):
133
+ iotests.log("=== Actual maximum size===")
134
+ iotests.log("")
135
+
136
+ blockdev_create(vm, { 'driver': imgfmt,
137
+ 'file': 'protocol-node',
138
+ 'size': 0xff000000 * 512,
139
+ 'force-size': True })
140
+
141
+
142
+def main():
143
+ for test_func in [implicit_defaults, explicit_defaults, non_defaults,
144
+ non_chs_size_without_force, zero_size, maximum_chs_size,
145
+ maximum_size]:
146
+
147
+ with iotests.FilePath('t.vpc') as file_path, \
148
+ iotests.VM() as vm:
149
+
150
+ vm.launch()
151
+
152
+ iotests.log('--- Creating empty file ---')
153
+ blockdev_create(vm, { 'driver': 'file',
154
+ 'filename': file_path,
155
+ 'size': 0 })
156
+
157
+ vm.qmp_log('blockdev-add', driver='file', filename=file_path,
158
+ node_name='protocol-node',
159
+ filters=[iotests.filter_qmp_testfiles])
160
+ iotests.log('')
161
+
162
+ print_info = test_func(vm, file_path)
163
+ iotests.log('')
164
+
165
+ vm.shutdown()
166
+ iotests.img_info_log(file_path)
167
+
168
+
169
+iotests.script_main(main,
170
+ supported_fmts=['vpc'],
171
+ supported_protocols=['file'])
172
diff --git a/tests/qemu-iotests/266.out b/tests/qemu-iotests/266.out
173
new file mode 100644
174
index XXXXXXX..XXXXXXX
175
--- /dev/null
176
+++ b/tests/qemu-iotests/266.out
177
@@ -XXX,XX +XXX,XX @@
178
+--- Creating empty file ---
179
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "size": 0}}}
180
+{"return": {}}
181
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
182
+{"return": {}}
183
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
184
+{"return": {}}
185
+
186
+=== Successful image creation (defaults) ===
187
+
188
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vpc", "file": "protocol-node", "size": 67125248}}}
189
+{"return": {}}
190
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
191
+{"return": {}}
192
+
193
+image: TEST_IMG
194
+file format: IMGFMT
195
+virtual size: 64 MiB (67125248 bytes)
196
+cluster_size: 2097152
197
+
198
+--- Creating empty file ---
199
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "size": 0}}}
200
+{"return": {}}
201
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
202
+{"return": {}}
203
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
204
+{"return": {}}
205
+
206
+=== Successful image creation (explicit defaults) ===
207
+
208
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vpc", "file": "protocol-node", "force-size": false, "size": 134250496, "subformat": "dynamic"}}}
209
+{"return": {}}
210
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
211
+{"return": {}}
212
+
213
+image: TEST_IMG
214
+file format: IMGFMT
215
+virtual size: 128 MiB (134250496 bytes)
216
+cluster_size: 2097152
217
+
218
+--- Creating empty file ---
219
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "size": 0}}}
220
+{"return": {}}
221
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
222
+{"return": {}}
223
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
224
+{"return": {}}
225
+
226
+=== Successful image creation (non-default options) ===
227
+
228
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vpc", "file": "protocol-node", "force-size": true, "size": 1048576, "subformat": "fixed"}}}
229
+{"return": {}}
230
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
231
+{"return": {}}
232
+
233
+image: TEST_IMG
234
+file format: IMGFMT
235
+virtual size: 1 MiB (1048576 bytes)
236
+
237
+--- Creating empty file ---
238
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "size": 0}}}
239
+{"return": {}}
240
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
241
+{"return": {}}
242
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
243
+{"return": {}}
244
+
245
+=== Size not representable in CHS ===
246
+
247
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vpc", "file": "protocol-node", "force-size": false, "size": 1048576}}}
248
+{"return": {}}
249
+Job failed: The requested image size cannot be represented in CHS geometry
250
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
251
+{"return": {}}
252
+
253
+qemu-img: Could not open 'TEST_IMG': File too small for a VHD header
254
+
255
+--- Creating empty file ---
256
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "size": 0}}}
257
+{"return": {}}
258
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
259
+{"return": {}}
260
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
261
+{"return": {}}
262
+
263
+=== Zero size===
264
+
265
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vpc", "file": "protocol-node", "size": 0}}}
266
+{"return": {}}
267
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
268
+{"return": {}}
269
+
270
+image: TEST_IMG
271
+file format: IMGFMT
272
+virtual size: 0 B (0 bytes)
273
+cluster_size: 2097152
274
+
275
+--- Creating empty file ---
276
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "size": 0}}}
277
+{"return": {}}
278
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
279
+{"return": {}}
280
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
281
+{"return": {}}
282
+
283
+=== Maximum CHS size===
284
+
285
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vpc", "file": "protocol-node", "size": 136899993600}}}
286
+{"return": {}}
287
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
288
+{"return": {}}
289
+
290
+image: TEST_IMG
291
+file format: IMGFMT
292
+virtual size: 127 GiB (136899993600 bytes)
293
+cluster_size: 2097152
294
+
295
+--- Creating empty file ---
296
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "size": 0}}}
297
+{"return": {}}
298
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
299
+{"return": {}}
300
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
301
+{"return": {}}
302
+
303
+=== Actual maximum size===
304
+
305
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vpc", "file": "protocol-node", "force-size": true, "size": 2190433320960}}}
306
+{"return": {}}
307
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
308
+{"return": {}}
309
+
310
+image: TEST_IMG
311
+file format: IMGFMT
312
+virtual size: 1.99 TiB (2190433320960 bytes)
313
+cluster_size: 2097152
314
+
315
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
316
index XXXXXXX..XXXXXXX 100644
317
--- a/tests/qemu-iotests/group
318
+++ b/tests/qemu-iotests/group
319
@@ -XXX,XX +XXX,XX @@
320
258 rw quick
321
262 rw quick migration
322
265 rw auto quick
323
+266 rw quick
324
--
106
--
325
2.20.1
107
2.13.6
326
108
327
109
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
Test that drain sections are correctly propagated through the graph.
2
2
3
The Valgrind tool fails to manage its termination in multi-threaded
4
processes when they raise the signal SIGKILL. The bug has been reported
5
to the Valgrind maintainers and was registered as the bug #409141:
6
https://bugs.kde.org/show_bug.cgi?id=409141
7
Let's exclude such test cases from running under the Valgrind until a
8
new version with the bug fix is released because checking for the
9
memory issues is covered by other test cases.
10
11
Suggested-by: John Snow <jsnow@redhat.com>
12
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
13
Reviewed-by: John Snow <jsnow@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
4
---
16
tests/qemu-iotests/039 | 5 +++++
5
tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
17
tests/qemu-iotests/061 | 2 ++
6
1 file changed, 74 insertions(+)
18
tests/qemu-iotests/137 | 1 +
19
tests/qemu-iotests/common.rc | 12 ++++++++++--
20
4 files changed, 18 insertions(+), 2 deletions(-)
21
7
22
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/039
25
+++ b/tests/qemu-iotests/039
26
@@ -XXX,XX +XXX,XX @@ echo "== Creating a dirty image file =="
27
IMGOPTS="compat=1.1,lazy_refcounts=on"
28
_make_test_img $size
29
30
+_NO_VALGRIND \
31
$QEMU_IO -c "write -P 0x5a 0 512" \
32
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
33
| _filter_qemu_io
34
@@ -XXX,XX +XXX,XX @@ echo "== Opening a dirty image read/write should repair it =="
35
IMGOPTS="compat=1.1,lazy_refcounts=on"
36
_make_test_img $size
37
38
+_NO_VALGRIND \
39
$QEMU_IO -c "write -P 0x5a 0 512" \
40
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
41
| _filter_qemu_io
42
@@ -XXX,XX +XXX,XX @@ echo "== Creating an image file with lazy_refcounts=off =="
43
IMGOPTS="compat=1.1,lazy_refcounts=off"
44
_make_test_img $size
45
46
+_NO_VALGRIND \
47
$QEMU_IO -c "write -P 0x5a 0 512" \
48
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
49
| _filter_qemu_io
50
@@ -XXX,XX +XXX,XX @@ echo "== Changing lazy_refcounts setting at runtime =="
51
IMGOPTS="compat=1.1,lazy_refcounts=off"
52
_make_test_img $size
53
54
+_NO_VALGRIND \
55
$QEMU_IO -c "reopen -o lazy-refcounts=on" \
56
-c "write -P 0x5a 0 512" \
57
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
58
@@ -XXX,XX +XXX,XX @@ _check_test_img
59
IMGOPTS="compat=1.1,lazy_refcounts=on"
60
_make_test_img $size
61
62
+_NO_VALGRIND \
63
$QEMU_IO -c "reopen -o lazy-refcounts=off" \
64
-c "write -P 0x5a 0 512" \
65
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
66
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
67
index XXXXXXX..XXXXXXX 100755
68
--- a/tests/qemu-iotests/061
69
+++ b/tests/qemu-iotests/061
70
@@ -XXX,XX +XXX,XX @@ echo
71
echo "=== Testing dirty version downgrade ==="
72
echo
73
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
74
+_NO_VALGRIND \
75
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
76
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
77
$PYTHON qcow2.py "$TEST_IMG" dump-header
78
@@ -XXX,XX +XXX,XX @@ echo
79
echo "=== Testing dirty lazy_refcounts=off ==="
80
echo
81
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
82
+_NO_VALGRIND \
83
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
84
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
85
$PYTHON qcow2.py "$TEST_IMG" dump-header
86
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
87
index XXXXXXX..XXXXXXX 100755
88
--- a/tests/qemu-iotests/137
89
+++ b/tests/qemu-iotests/137
90
@@ -XXX,XX +XXX,XX @@ echo
91
92
# Whether lazy-refcounts was actually enabled can easily be tested: Check if
93
# the dirty bit is set after a crash
94
+_NO_VALGRIND \
95
$QEMU_IO \
96
-c "reopen -o lazy-refcounts=on,overlap-check=blubb" \
97
-c "write -P 0x5a 0 512" \
98
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
99
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
100
--- a/tests/qemu-iotests/common.rc
10
--- a/tests/test-bdrv-drain.c
101
+++ b/tests/qemu-iotests/common.rc
11
+++ b/tests/test-bdrv-drain.c
102
@@ -XXX,XX +XXX,XX @@ _qemu_proc_exec()
12
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
103
{
13
blk_unref(blk);
104
local VALGRIND_LOGFILE="$1"
105
shift
106
- if [ "${VALGRIND_QEMU}" == "y" ]; then
107
+ if [[ "${VALGRIND_QEMU}" == "y" && "${NO_VALGRIND}" != "y" ]]; then
108
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$@"
109
else
110
exec "$@"
111
@@ -XXX,XX +XXX,XX @@ _qemu_proc_valgrind_log()
112
{
113
local VALGRIND_LOGFILE="$1"
114
local RETVAL="$2"
115
- if [ "${VALGRIND_QEMU}" == "y" ]; then
116
+ if [[ "${VALGRIND_QEMU}" == "y" && "${NO_VALGRIND}" != "y" ]]; then
117
if [ $RETVAL == 99 ]; then
118
cat "${VALGRIND_LOGFILE}"
119
fi
120
@@ -XXX,XX +XXX,XX @@ _qemu_vxhs_wrapper()
121
return $RETVAL
122
}
14
}
123
15
124
+# Valgrind bug #409141 https://bugs.kde.org/show_bug.cgi?id=409141
16
+static void test_multiparent(void)
125
+# Until valgrind 3.16+ is ubiquitous, we must work around a hang in
126
+# valgrind when issuing sigkill. Disable valgrind for this invocation.
127
+_NO_VALGRIND()
128
+{
17
+{
129
+ NO_VALGRIND="y" "$@"
18
+ BlockBackend *blk_a, *blk_b;
19
+ BlockDriverState *bs_a, *bs_b, *backing;
20
+ BDRVTestState *a_s, *b_s, *backing_s;
21
+
22
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
23
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
24
+ &error_abort);
25
+ a_s = bs_a->opaque;
26
+ blk_insert_bs(blk_a, bs_a, &error_abort);
27
+
28
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
29
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
30
+ &error_abort);
31
+ b_s = bs_b->opaque;
32
+ blk_insert_bs(blk_b, bs_b, &error_abort);
33
+
34
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
35
+ backing_s = backing->opaque;
36
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
37
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
38
+
39
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
40
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
41
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(a_s->drain_count, ==, 0);
43
+ g_assert_cmpint(b_s->drain_count, ==, 0);
44
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
45
+
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
47
+
48
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
49
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
50
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
51
+ g_assert_cmpint(a_s->drain_count, ==, 1);
52
+ g_assert_cmpint(b_s->drain_count, ==, 1);
53
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
54
+
55
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
56
+
57
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 2);
58
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
59
+ g_assert_cmpint(backing->quiesce_counter, ==, 2);
60
+ g_assert_cmpint(a_s->drain_count, ==, 2);
61
+ g_assert_cmpint(b_s->drain_count, ==, 2);
62
+ g_assert_cmpint(backing_s->drain_count, ==, 2);
63
+
64
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
65
+
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
69
+ g_assert_cmpint(a_s->drain_count, ==, 1);
70
+ g_assert_cmpint(b_s->drain_count, ==, 1);
71
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
72
+
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
74
+
75
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
76
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
77
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
78
+ g_assert_cmpint(a_s->drain_count, ==, 0);
79
+ g_assert_cmpint(b_s->drain_count, ==, 0);
80
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
81
+
82
+ bdrv_unref(backing);
83
+ bdrv_unref(bs_a);
84
+ bdrv_unref(bs_b);
85
+ blk_unref(blk_a);
86
+ blk_unref(blk_b);
130
+}
87
+}
131
+
88
+
132
export QEMU=_qemu_wrapper
89
133
export QEMU_IMG=_qemu_img_wrapper
90
typedef struct TestBlockJob {
134
export QEMU_IO=_qemu_io_wrapper
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);
135
--
100
--
136
2.20.1
101
2.13.6
137
102
138
103
diff view generated by jsdifflib
New patch
1
1
We need to remember how many of the drain sections in which a node is
2
were recursive (i.e. subtree drain rather than node drain), so that they
3
can be correctly applied when children are added or removed during the
4
drained section.
5
6
With this change, it is safe to modify the graph even inside a
7
bdrv_subtree_drained_begin/end() section.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
include/block/block.h | 2 --
12
include/block/block_int.h | 5 +++++
13
block.c | 32 +++++++++++++++++++++++++++++---
14
block/io.c | 28 ++++++++++++++++++++++++----
15
4 files changed, 58 insertions(+), 9 deletions(-)
16
17
diff --git a/include/block/block.h b/include/block/block.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/block.h
20
+++ b/include/block/block.h
21
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs);
22
/**
23
* Like bdrv_drained_begin, but recursively begins a quiesced section for
24
* exclusive access to all child nodes as well.
25
- *
26
- * Graph changes are not allowed during a subtree drain section.
27
*/
28
void bdrv_subtree_drained_begin(BlockDriverState *bs);
29
30
diff --git a/include/block/block_int.h b/include/block/block_int.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/block/block_int.h
33
+++ b/include/block/block_int.h
34
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
35
36
/* Accessed with atomic ops. */
37
int quiesce_counter;
38
+ int recursive_quiesce_counter;
39
+
40
unsigned int write_gen; /* Current data generation */
41
42
/* Protected by reqs_lock. */
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
44
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
45
BdrvRequestFlags flags);
46
47
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent);
48
+void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent);
49
+
50
int get_tmp_filename(char *filename, int size);
51
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
52
const char *filename);
53
diff --git a/block.c b/block.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block.c
56
+++ b/block.c
57
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_end(BdrvChild *child)
58
bdrv_drained_end(bs);
59
}
60
61
+static void bdrv_child_cb_attach(BdrvChild *child)
62
+{
63
+ BlockDriverState *bs = child->opaque;
64
+ bdrv_apply_subtree_drain(child, bs);
65
+}
66
+
67
+static void bdrv_child_cb_detach(BdrvChild *child)
68
+{
69
+ BlockDriverState *bs = child->opaque;
70
+ bdrv_unapply_subtree_drain(child, bs);
71
+}
72
+
73
static int bdrv_child_cb_inactivate(BdrvChild *child)
74
{
75
BlockDriverState *bs = child->opaque;
76
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_file = {
77
.inherit_options = bdrv_inherited_options,
78
.drained_begin = bdrv_child_cb_drained_begin,
79
.drained_end = bdrv_child_cb_drained_end,
80
+ .attach = bdrv_child_cb_attach,
81
+ .detach = bdrv_child_cb_detach,
82
.inactivate = bdrv_child_cb_inactivate,
83
};
84
85
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
86
.inherit_options = bdrv_inherited_fmt_options,
87
.drained_begin = bdrv_child_cb_drained_begin,
88
.drained_end = bdrv_child_cb_drained_end,
89
+ .attach = bdrv_child_cb_attach,
90
+ .detach = bdrv_child_cb_detach,
91
.inactivate = bdrv_child_cb_inactivate,
92
};
93
94
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_attach(BdrvChild *c)
95
parent->backing_blocker);
96
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
97
parent->backing_blocker);
98
+
99
+ bdrv_child_cb_attach(c);
100
}
101
102
static void bdrv_backing_detach(BdrvChild *c)
103
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c)
104
bdrv_op_unblock_all(c->bs, parent->backing_blocker);
105
error_free(parent->backing_blocker);
106
parent->backing_blocker = NULL;
107
+
108
+ bdrv_child_cb_detach(c);
109
}
110
111
/*
112
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
113
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
114
}
115
if (old_bs) {
116
+ /* Detach first so that the recursive drain sections coming from @child
117
+ * are already gone and we only end the drain sections that came from
118
+ * elsewhere. */
119
+ if (child->role->detach) {
120
+ child->role->detach(child);
121
+ }
122
if (old_bs->quiesce_counter && child->role->drained_end) {
123
for (i = 0; i < old_bs->quiesce_counter; i++) {
124
child->role->drained_end(child);
125
}
126
}
127
- if (child->role->detach) {
128
- child->role->detach(child);
129
- }
130
QLIST_REMOVE(child, next_parent);
131
}
132
133
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
134
}
135
}
136
137
+ /* Attach only after starting new drained sections, so that recursive
138
+ * drain sections coming from @child don't get an extra .drained_begin
139
+ * callback. */
140
if (child->role->attach) {
141
child->role->attach(child);
142
}
143
diff --git a/block/io.c b/block/io.c
144
index XXXXXXX..XXXXXXX 100644
145
--- a/block/io.c
146
+++ b/block/io.c
147
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
148
assert(data.done);
149
}
150
151
-static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
152
- BdrvChild *parent)
153
+void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
154
+ BdrvChild *parent)
155
{
156
BdrvChild *child, *next;
157
158
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
159
bdrv_drain_recurse(bs);
160
161
if (recursive) {
162
+ bs->recursive_quiesce_counter++;
163
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
164
bdrv_do_drained_begin(child->bs, true, child);
165
}
166
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_begin(BlockDriverState *bs)
167
bdrv_do_drained_begin(bs, true, NULL);
168
}
169
170
-static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
171
- BdrvChild *parent)
172
+void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
173
+ BdrvChild *parent)
174
{
175
BdrvChild *child, *next;
176
int old_quiesce_counter;
177
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
178
}
179
180
if (recursive) {
181
+ bs->recursive_quiesce_counter--;
182
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
183
bdrv_do_drained_end(child->bs, true, child);
184
}
185
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_end(BlockDriverState *bs)
186
bdrv_do_drained_end(bs, true, NULL);
187
}
188
189
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
190
+{
191
+ int i;
192
+
193
+ for (i = 0; i < new_parent->recursive_quiesce_counter; i++) {
194
+ bdrv_do_drained_begin(child->bs, true, child);
195
+ }
196
+}
197
+
198
+void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
199
+{
200
+ int i;
201
+
202
+ for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
203
+ bdrv_do_drained_end(child->bs, true, child);
204
+ }
205
+}
206
+
207
/*
208
* Wait for pending requests to complete on a single BlockDriverState subtree,
209
* and suspend block driver's internal I/O until next request arrives.
210
--
211
2.13.6
212
213
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
2
3
pr_manager_worker() passes its @opaque argument to g_free(). Wrong;
4
it points to pr_manager_worker()'s automatic @data. Broken when
5
commit 2f3a7ab39be converted @data from heap- to stack-allocated. Fix
6
by deleting the g_free().
7
8
Fixes: 2f3a7ab39bec4ba8022dc4d42ea641165b004e3e
9
Cc: qemu-stable@nongnu.org
10
Signed-off-by: Markus Armbruster <armbru@redhat.com>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
2
---
15
scsi/pr-manager.c | 1 -
3
tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
16
1 file changed, 1 deletion(-)
4
1 file changed, 80 insertions(+)
17
5
18
diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
19
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
20
--- a/scsi/pr-manager.c
8
--- a/tests/test-bdrv-drain.c
21
+++ b/scsi/pr-manager.c
9
+++ b/tests/test-bdrv-drain.c
22
@@ -XXX,XX +XXX,XX @@ static int pr_manager_worker(void *opaque)
10
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
23
int fd = data->fd;
11
blk_unref(blk_b);
24
int r;
12
}
25
13
26
- g_free(data);
14
+static void test_graph_change(void)
27
trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]);
15
+{
28
16
+ BlockBackend *blk_a, *blk_b;
29
/* The reference was taken in pr_manager_execute. */
17
+ BlockDriverState *bs_a, *bs_b, *backing;
18
+ BDRVTestState *a_s, *b_s, *backing_s;
19
+
20
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
21
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
22
+ &error_abort);
23
+ a_s = bs_a->opaque;
24
+ blk_insert_bs(blk_a, bs_a, &error_abort);
25
+
26
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
27
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
28
+ &error_abort);
29
+ b_s = bs_b->opaque;
30
+ blk_insert_bs(blk_b, bs_b, &error_abort);
31
+
32
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
33
+ backing_s = backing->opaque;
34
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
35
+
36
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
37
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
38
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
39
+ g_assert_cmpint(a_s->drain_count, ==, 0);
40
+ g_assert_cmpint(b_s->drain_count, ==, 0);
41
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
42
+
43
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
44
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
45
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
47
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
48
+
49
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
50
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
51
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
52
+ g_assert_cmpint(backing->quiesce_counter, ==, 5);
53
+ g_assert_cmpint(a_s->drain_count, ==, 5);
54
+ g_assert_cmpint(b_s->drain_count, ==, 5);
55
+ g_assert_cmpint(backing_s->drain_count, ==, 5);
56
+
57
+ bdrv_set_backing_hd(bs_b, NULL, &error_abort);
58
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 3);
59
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
60
+ g_assert_cmpint(backing->quiesce_counter, ==, 3);
61
+ g_assert_cmpint(a_s->drain_count, ==, 3);
62
+ g_assert_cmpint(b_s->drain_count, ==, 2);
63
+ g_assert_cmpint(backing_s->drain_count, ==, 3);
64
+
65
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 5);
69
+ g_assert_cmpint(a_s->drain_count, ==, 5);
70
+ g_assert_cmpint(b_s->drain_count, ==, 5);
71
+ g_assert_cmpint(backing_s->drain_count, ==, 5);
72
+
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
74
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
75
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
76
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
77
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
78
+
79
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
80
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
81
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
82
+ g_assert_cmpint(a_s->drain_count, ==, 0);
83
+ g_assert_cmpint(b_s->drain_count, ==, 0);
84
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
85
+
86
+ bdrv_unref(backing);
87
+ bdrv_unref(bs_a);
88
+ bdrv_unref(bs_b);
89
+ blk_unref(blk_a);
90
+ blk_unref(blk_b);
91
+}
92
+
93
94
typedef struct TestBlockJob {
95
BlockJob common;
96
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
97
98
g_test_add_func("/bdrv-drain/nested", test_nested);
99
g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
100
+ g_test_add_func("/bdrv-drain/graph-change", test_graph_change);
101
102
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
103
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
30
--
104
--
31
2.20.1
105
2.13.6
32
106
33
107
diff view generated by jsdifflib
New patch
1
Since commit bde70715, base is the only node that is reopened in
2
commit_start(). This means that the code, which still involves an
3
explicit BlockReopenQueue, can now be simplified by using bdrv_reopen().
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Fam Zheng <famz@redhat.com>
7
---
8
block/commit.c | 8 +-------
9
1 file changed, 1 insertion(+), 7 deletions(-)
10
11
diff --git a/block/commit.c b/block/commit.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/commit.c
14
+++ b/block/commit.c
15
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
16
const char *filter_node_name, Error **errp)
17
{
18
CommitBlockJob *s;
19
- BlockReopenQueue *reopen_queue = NULL;
20
int orig_base_flags;
21
BlockDriverState *iter;
22
BlockDriverState *commit_top_bs = NULL;
23
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
24
/* convert base to r/w, if necessary */
25
orig_base_flags = bdrv_get_flags(base);
26
if (!(orig_base_flags & BDRV_O_RDWR)) {
27
- reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
28
- orig_base_flags | BDRV_O_RDWR);
29
- }
30
-
31
- if (reopen_queue) {
32
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
33
+ bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
34
if (local_err != NULL) {
35
error_propagate(errp, local_err);
36
goto fail;
37
--
38
2.13.6
39
40
diff view generated by jsdifflib
1
qemu_io_alloc_from_file() needs to close the pattern file even if some
1
The bdrv_reopen*() implementation doesn't like it if the graph is
2
error occurred.
2
changed between queuing nodes for reopen and actually reopening them
3
(one of the reasons is that queuing can be recursive).
3
4
4
Setting f = NULL in the success path and checking it for NULL in the
5
So instead of draining the device only in bdrv_reopen_multiple(),
5
error path isn't strictly necessary at this point, but let's do it
6
require that callers already drained all affected nodes, and assert this
6
anyway in case someone later adds a 'goto error' after closing the file.
7
in bdrv_reopen_queue().
7
8
8
Coverity: CID 1405303
9
Fixes: 4d731510d34f280ed45a6de621d016f67a49ea48
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
12
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
13
---
11
---
14
qemu-io-cmds.c | 4 ++++
12
block.c | 23 ++++++++++++++++-------
15
1 file changed, 4 insertions(+)
13
block/replication.c | 6 ++++++
14
qemu-io-cmds.c | 3 +++
15
3 files changed, 25 insertions(+), 7 deletions(-)
16
16
17
diff --git a/block.c b/block.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/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;
63
@@ -XXX,XX +XXX,XX @@ cleanup:
64
}
65
g_free(bs_queue);
66
67
- bdrv_drain_all_end();
68
-
69
return ret;
70
}
71
72
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
73
{
74
int ret = -1;
75
Error *local_err = NULL;
76
- BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
77
+ BlockReopenQueue *queue;
78
79
+ bdrv_subtree_drained_begin(bs);
80
+
81
+ queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
82
ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err);
83
if (local_err != NULL) {
84
error_propagate(errp, local_err);
85
}
86
+
87
+ bdrv_subtree_drained_end(bs);
88
+
89
return ret;
90
}
91
92
diff --git a/block/replication.c b/block/replication.c
93
index XXXXXXX..XXXXXXX 100644
94
--- a/block/replication.c
95
+++ b/block/replication.c
96
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
97
new_secondary_flags = s->orig_secondary_flags;
98
}
99
100
+ bdrv_subtree_drained_begin(s->hidden_disk->bs);
101
+ bdrv_subtree_drained_begin(s->secondary_disk->bs);
102
+
103
if (orig_hidden_flags != new_hidden_flags) {
104
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
105
new_hidden_flags);
106
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
107
reopen_queue, &local_err);
108
error_propagate(errp, local_err);
109
}
110
+
111
+ bdrv_subtree_drained_end(s->hidden_disk->bs);
112
+ bdrv_subtree_drained_end(s->secondary_disk->bs);
113
}
114
115
static void backup_job_cleanup(BlockDriverState *bs)
17
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
116
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
18
index XXXXXXX..XXXXXXX 100644
117
index XXXXXXX..XXXXXXX 100644
19
--- a/qemu-io-cmds.c
118
--- a/qemu-io-cmds.c
20
+++ b/qemu-io-cmds.c
119
+++ b/qemu-io-cmds.c
21
@@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
120
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
22
}
121
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
23
122
qemu_opts_reset(&reopen_opts);
24
fclose(f);
123
25
+ f = NULL;
124
+ bdrv_subtree_drained_begin(bs);
26
125
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
27
if (len > pattern_len) {
126
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
28
len -= pattern_len;
127
+ bdrv_subtree_drained_end(bs);
29
@@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
128
+
30
129
if (local_err) {
31
error:
130
error_report_err(local_err);
32
qemu_io_free(buf_origin);
131
} else {
33
+ if (f) {
34
+ fclose(f);
35
+ }
36
return NULL;
37
}
38
39
--
132
--
40
2.20.1
133
2.13.6
41
134
42
135
diff view generated by jsdifflib