1
The following changes since commit aceeaa69d28e6f08a24395d0aa6915b687d0a681:
1
The following changes since commit 281f327487c9c9b1599f93c589a408bbf4a651b8:
2
2
3
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2019-12-17' into staging (2019-12-17 15:55:20 +0000)
3
Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.12-pull-request' into staging (2017-12-22 00:11:36 +0000)
4
4
5
are available in the Git repository at:
5
are available in the git repository at:
6
6
7
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 f62f08ab7a9d902da70078992248ec5c98f652ad:
9
for you to fetch changes up to 1a63a907507fbbcfaee3f622907ec244b7eabda8:
10
10
11
iotests: Test external snapshot with VM state (2019-12-19 18:04:25 +0100)
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
- qemu-img: fix info --backing-chain --image-opts
17
- Error out on image creation with conflicting size options
18
- Fix external snapshot with VM state
19
- hmp: Allow using qdev ID for qemu-io command
20
- Misc code cleanup
21
- Many iotests improvements
22
15
23
----------------------------------------------------------------
16
----------------------------------------------------------------
24
Alberto Garcia (1):
17
Doug Gale (1):
25
qcow2: Use offset_into_cluster()
18
nvme: Add tracing
26
19
27
Daniel P. Berrangé (1):
20
Edgar Kaziakhmedov (1):
28
qapi: better document NVMe blockdev @device parameter
21
qcow2: get rid of qcow2_backing_read1 routine
29
22
30
Kevin Wolf (19):
23
Fam Zheng (2):
31
block: Error out on image creation with conflicting size options
24
block: Open backing image in force share mode for size probe
32
blockjob: Fix error message for negative speed
25
block: Remove unused bdrv_requests_pending
33
qcow2: Declare BDRV_REQ_NO_FALLBACK supported
34
iotests: Add qemu_io_log()
35
iotests: Fix timeout in run_job()
36
iotests: Support job-complete in run_job()
37
iotests: Create VM.blockdev_create()
38
iotests: 255: Drop blockdev_create()
39
iotests: 206: Convert to VM.blockdev_create()
40
iotests: 210: Convert to VM.blockdev_create()
41
iotests: 212: Convert to VM.blockdev_create()
42
iotests: 213: Convert to VM.blockdev_create()
43
iotests: 237: Convert to VM.blockdev_create()
44
iotests: 266: Convert to VM.blockdev_create()
45
iotests: 207: Remove duplication with VM.blockdev_create()
46
iotests: 211: Remove duplication with VM.blockdev_create()
47
block: Activate recursively even for already active nodes
48
hmp: Allow using qdev ID for qemu-io command
49
iotests: Test external snapshot with VM state
50
26
51
Max Reitz (2):
27
John Snow (1):
52
iotests/273: Filter format-specific information
28
iotests: fix 197 for vpc
53
iotests: Fix IMGOPTSSYNTAX for nbd
54
29
55
Stefan Hajnoczi (1):
30
Kevin Wolf (27):
56
qemu-img: fix info --backing-chain --image-opts
31
block: Formats don't need CONSISTENT_READ with NO_IO
32
block: Make bdrv_drain_invoke() recursive
33
block: Call .drain_begin only once in bdrv_drain_all_begin()
34
test-bdrv-drain: Test BlockDriver callbacks for drain
35
block: bdrv_drain_recurse(): Remove unused begin parameter
36
block: Don't wait for requests in bdrv_drain*_end()
37
block: Unify order in drain functions
38
block: Don't acquire AioContext in hmp_qemu_io()
39
block: Document that x-blockdev-change breaks quorum children list
40
block: Assert drain_all is only called from main AioContext
41
block: Make bdrv_drain() driver callbacks non-recursive
42
test-bdrv-drain: Test callback for bdrv_drain
43
test-bdrv-drain: Test bs->quiesce_counter
44
blockjob: Pause job on draining any job BDS
45
test-bdrv-drain: Test drain vs. block jobs
46
block: Don't block_job_pause_all() in bdrv_drain_all()
47
block: Nested drain_end must still call callbacks
48
test-bdrv-drain: Test nested drain sections
49
block: Don't notify parents in drain call chain
50
block: Add bdrv_subtree_drained_begin/end()
51
test-bdrv-drain: Tests for bdrv_subtree_drain
52
test-bdrv-drain: Test behaviour in coroutine context
53
test-bdrv-drain: Recursive draining with multiple parents
54
block: Allow graph changes in subtree drained section
55
test-bdrv-drain: Test graph changes in drained section
56
commit: Simplify reopen of base
57
block: Keep nodes drained between reopen_queue/multiple
57
58
58
Thomas Huth (4):
59
Thomas Huth (3):
59
iotests: Provide a function for checking the creation of huge files
60
block: Remove the obsolete -drive boot=on|off parameter
60
iotests: Skip test 060 if it is not possible to create large files
61
block: Remove the deprecated -hdachs option
61
iotests: Skip test 079 if it is not possible to create large files
62
block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter
62
iotests: Add more "_require_drivers" checks to the shell-based tests
63
63
64
Tuguoyi (1):
64
qapi/block-core.json | 4 +
65
qcow2: Move error check of local_err near its assignment
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
66
88
67
Vladimir Sementsov-Ogievskiy (1):
68
MAINTAINERS: fix qcow2-bitmap.c under Dirty Bitmaps header
69
70
qapi/block-core.json | 6 +-
71
block.c | 60 ++++++-----
72
block/qcow2.c | 21 ++--
73
blockjob.c | 3 +-
74
monitor/hmp-cmds.c | 28 +++--
75
qemu-img.c | 3 +
76
MAINTAINERS | 6 +-
77
hmp-commands.hx | 8 +-
78
tests/qemu-iotests/005 | 5 +-
79
tests/qemu-iotests/030 | 4 +-
80
tests/qemu-iotests/049 | 5 +
81
tests/qemu-iotests/049.out | 5 +
82
tests/qemu-iotests/051 | 1 +
83
tests/qemu-iotests/060 | 3 +
84
tests/qemu-iotests/079 | 3 +
85
tests/qemu-iotests/206 | 232 ++++++++++++++++++++----------------------
86
tests/qemu-iotests/207 | 8 +-
87
tests/qemu-iotests/210 | 81 +++++++--------
88
tests/qemu-iotests/211 | 12 +--
89
tests/qemu-iotests/212 | 101 +++++++++---------
90
tests/qemu-iotests/213 | 113 ++++++++++----------
91
tests/qemu-iotests/220 | 6 +-
92
tests/qemu-iotests/237 | 139 ++++++++++++-------------
93
tests/qemu-iotests/255 | 10 --
94
tests/qemu-iotests/266 | 69 ++++++-------
95
tests/qemu-iotests/266.out | 14 +++
96
tests/qemu-iotests/267 | 1 +
97
tests/qemu-iotests/273 | 3 +-
98
tests/qemu-iotests/273.out | 27 -----
99
tests/qemu-iotests/279 | 57 +++++++++++
100
tests/qemu-iotests/279.out | 35 +++++++
101
tests/qemu-iotests/280 | 83 +++++++++++++++
102
tests/qemu-iotests/280.out | 50 +++++++++
103
tests/qemu-iotests/common.rc | 13 ++-
104
tests/qemu-iotests/group | 2 +
105
tests/qemu-iotests/iotests.py | 25 ++++-
106
36 files changed, 724 insertions(+), 518 deletions(-)
107
create mode 100755 tests/qemu-iotests/279
108
create mode 100644 tests/qemu-iotests/279.out
109
create mode 100755 tests/qemu-iotests/280
110
create mode 100644 tests/qemu-iotests/280.out
111
112
diff view generated by jsdifflib
1
Instead of having a separate blockdev_create() function, make use of the
1
Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently
2
VM.blockdev_create() offered by iotests.py.
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.
4
5
As this permission is geared towards whether the guest-visible data is
6
consistent, and has no impact on whether the metadata is sane, and
7
'qemu-img info' does not read guest-visible data (except for the raw
8
format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there
9
is not going to be any guest I/O performed, regardless of image format.
3
10
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
12
---
6
tests/qemu-iotests/266 | 69 +++++++++++++++++---------------------
13
block.c | 6 +++++-
7
tests/qemu-iotests/266.out | 14 ++++++++
14
1 file changed, 5 insertions(+), 1 deletion(-)
8
2 files changed, 44 insertions(+), 39 deletions(-)
9
15
10
diff --git a/tests/qemu-iotests/266 b/tests/qemu-iotests/266
16
diff --git a/block.c b/block.c
11
index XXXXXXX..XXXXXXX 100755
12
--- a/tests/qemu-iotests/266
13
+++ b/tests/qemu-iotests/266
14
@@ -XXX,XX +XXX,XX @@ import iotests
15
from iotests import imgfmt
16
17
18
-def blockdev_create(vm, options):
19
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
20
- filters=[iotests.filter_qmp_testfiles])
21
-
22
- if 'return' in result:
23
- assert result['return'] == {}
24
- vm.run_job('job0')
25
-
26
-
27
# Successful image creation (defaults)
28
def implicit_defaults(vm, file_path):
29
iotests.log("=== Successful image creation (defaults) ===")
30
@@ -XXX,XX +XXX,XX @@ def implicit_defaults(vm, file_path):
31
# (Close to 64 MB)
32
size = 8 * 964 * 17 * 512
33
34
- blockdev_create(vm, { 'driver': imgfmt,
35
- 'file': 'protocol-node',
36
- 'size': size })
37
+ vm.blockdev_create({ 'driver': imgfmt,
38
+ 'file': 'protocol-node',
39
+ 'size': size })
40
41
42
# Successful image creation (explicit defaults)
43
@@ -XXX,XX +XXX,XX @@ def explicit_defaults(vm, file_path):
44
# (Close to 128 MB)
45
size = 16 * 964 * 17 * 512
46
47
- blockdev_create(vm, { 'driver': imgfmt,
48
- 'file': 'protocol-node',
49
- 'size': size,
50
- 'subformat': 'dynamic',
51
- 'force-size': False })
52
+ vm.blockdev_create({ 'driver': imgfmt,
53
+ 'file': 'protocol-node',
54
+ 'size': size,
55
+ 'subformat': 'dynamic',
56
+ 'force-size': False })
57
58
59
# Successful image creation (non-default options)
60
@@ -XXX,XX +XXX,XX @@ def non_defaults(vm, file_path):
61
# Not representable in CHS (fine with force-size=True)
62
size = 1048576
63
64
- blockdev_create(vm, { 'driver': imgfmt,
65
- 'file': 'protocol-node',
66
- 'size': size,
67
- 'subformat': 'fixed',
68
- 'force-size': True })
69
+ vm.blockdev_create({ 'driver': imgfmt,
70
+ 'file': 'protocol-node',
71
+ 'size': size,
72
+ 'subformat': 'fixed',
73
+ 'force-size': True })
74
75
76
# Size not representable in CHS with force-size=False
77
@@ -XXX,XX +XXX,XX @@ def non_chs_size_without_force(vm, file_path):
78
# Not representable in CHS (will not work with force-size=False)
79
size = 1048576
80
81
- blockdev_create(vm, { 'driver': imgfmt,
82
- 'file': 'protocol-node',
83
- 'size': size,
84
- 'force-size': False })
85
+ vm.blockdev_create({ 'driver': imgfmt,
86
+ 'file': 'protocol-node',
87
+ 'size': size,
88
+ 'force-size': False })
89
90
91
# Zero size
92
@@ -XXX,XX +XXX,XX @@ def zero_size(vm, file_path):
93
iotests.log("=== Zero size===")
94
iotests.log("")
95
96
- blockdev_create(vm, { 'driver': imgfmt,
97
- 'file': 'protocol-node',
98
- 'size': 0 })
99
+ vm.blockdev_create({ 'driver': imgfmt,
100
+ 'file': 'protocol-node',
101
+ 'size': 0 })
102
103
104
# Maximum CHS size
105
@@ -XXX,XX +XXX,XX @@ def maximum_chs_size(vm, file_path):
106
iotests.log("=== Maximum CHS size===")
107
iotests.log("")
108
109
- blockdev_create(vm, { 'driver': imgfmt,
110
- 'file': 'protocol-node',
111
- 'size': 16 * 65535 * 255 * 512 })
112
+ vm.blockdev_create({ 'driver': imgfmt,
113
+ 'file': 'protocol-node',
114
+ 'size': 16 * 65535 * 255 * 512 })
115
116
117
# Actual maximum size
118
@@ -XXX,XX +XXX,XX @@ def maximum_size(vm, file_path):
119
iotests.log("=== Actual maximum size===")
120
iotests.log("")
121
122
- blockdev_create(vm, { 'driver': imgfmt,
123
- 'file': 'protocol-node',
124
- 'size': 0xff000000 * 512,
125
- 'force-size': True })
126
+ vm.blockdev_create({ 'driver': imgfmt,
127
+ 'file': 'protocol-node',
128
+ 'size': 0xff000000 * 512,
129
+ 'force-size': True })
130
131
132
def main():
133
@@ -XXX,XX +XXX,XX @@ def main():
134
vm.launch()
135
136
iotests.log('--- Creating empty file ---')
137
- blockdev_create(vm, { 'driver': 'file',
138
- 'filename': file_path,
139
- 'size': 0 })
140
+ vm.blockdev_create({ 'driver': 'file',
141
+ 'filename': file_path,
142
+ 'size': 0 })
143
144
vm.qmp_log('blockdev-add', driver='file', filename=file_path,
145
node_name='protocol-node',
146
diff --git a/tests/qemu-iotests/266.out b/tests/qemu-iotests/266.out
147
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
148
--- a/tests/qemu-iotests/266.out
18
--- a/block.c
149
+++ b/tests/qemu-iotests/266.out
19
+++ b/block.c
150
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
151
{"return": {}}
21
assert(role == &child_backing || role == &child_file);
152
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
22
153
{"return": {}}
23
if (!backing) {
24
+ int flags = bdrv_reopen_get_flags(reopen_queue, bs);
154
+
25
+
155
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
26
/* Apart from the modifications below, the same permissions are
156
{"return": {}}
27
* forwarded and left alone as for filters */
157
28
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
158
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
159
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
30
160
{"return": {}}
31
/* bs->file always needs to be consistent because of the metadata. We
161
32
* can never allow other users to resize or write to it. */
162
+
33
- perm |= BLK_PERM_CONSISTENT_READ;
163
image: TEST_IMG
34
+ if (!(flags & BDRV_O_NO_IO)) {
164
file format: IMGFMT
35
+ perm |= BLK_PERM_CONSISTENT_READ;
165
virtual size: 64 MiB (67125248 bytes)
36
+ }
166
@@ -XXX,XX +XXX,XX @@ cluster_size: 2097152
37
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
167
{"return": {}}
38
} else {
168
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
39
/* We want consistent read from backing files if the parent needs it.
169
{"return": {}}
170
+
171
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
172
{"return": {}}
173
174
@@ -XXX,XX +XXX,XX @@ cluster_size: 2097152
175
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
176
{"return": {}}
177
178
+
179
image: TEST_IMG
180
file format: IMGFMT
181
virtual size: 128 MiB (134250496 bytes)
182
@@ -XXX,XX +XXX,XX @@ cluster_size: 2097152
183
{"return": {}}
184
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
185
{"return": {}}
186
+
187
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
188
{"return": {}}
189
190
@@ -XXX,XX +XXX,XX @@ cluster_size: 2097152
191
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
192
{"return": {}}
193
194
+
195
image: TEST_IMG
196
file format: IMGFMT
197
virtual size: 1 MiB (1048576 bytes)
198
@@ -XXX,XX +XXX,XX @@ virtual size: 1 MiB (1048576 bytes)
199
{"return": {}}
200
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
201
{"return": {}}
202
+
203
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
204
{"return": {}}
205
206
@@ -XXX,XX +XXX,XX @@ Job failed: The requested image size cannot be represented in CHS geometry
207
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
208
{"return": {}}
209
210
+
211
qemu-img: Could not open 'TEST_IMG': File too small for a VHD header
212
213
--- Creating empty file ---
214
@@ -XXX,XX +XXX,XX @@ qemu-img: Could not open 'TEST_IMG': File too small for a VHD header
215
{"return": {}}
216
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
217
{"return": {}}
218
+
219
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
220
{"return": {}}
221
222
@@ -XXX,XX +XXX,XX @@ qemu-img: Could not open 'TEST_IMG': File too small for a VHD header
223
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
224
{"return": {}}
225
226
+
227
image: TEST_IMG
228
file format: IMGFMT
229
virtual size: 0 B (0 bytes)
230
@@ -XXX,XX +XXX,XX @@ cluster_size: 2097152
231
{"return": {}}
232
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
233
{"return": {}}
234
+
235
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
236
{"return": {}}
237
238
@@ -XXX,XX +XXX,XX @@ cluster_size: 2097152
239
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
240
{"return": {}}
241
242
+
243
image: TEST_IMG
244
file format: IMGFMT
245
virtual size: 127 GiB (136899993600 bytes)
246
@@ -XXX,XX +XXX,XX @@ cluster_size: 2097152
247
{"return": {}}
248
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
249
{"return": {}}
250
+
251
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vpc", "node-name": "protocol-node"}}
252
{"return": {}}
253
254
@@ -XXX,XX +XXX,XX @@ cluster_size: 2097152
255
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
256
{"return": {}}
257
258
+
259
image: TEST_IMG
260
file format: IMGFMT
261
virtual size: 1.99 TiB (2190433320960 bytes)
262
--
40
--
263
2.20.1
41
2.13.6
264
42
265
43
diff view generated by jsdifflib
New patch
1
From: John Snow <jsnow@redhat.com>
1
2
3
VPC has some difficulty creating geometries of particular size.
4
However, we can indeed force it to use a literal one, so let's
5
do that for the sake of test 197, which is testing some specific
6
offsets.
7
8
Signed-off-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Lukáš Doktor <ldoktor@redhat.com>
13
---
14
tests/qemu-iotests/197 | 4 ++++
15
tests/qemu-iotests/common.filter | 3 ++-
16
2 files changed, 6 insertions(+), 1 deletion(-)
17
18
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/197
21
+++ b/tests/qemu-iotests/197
22
@@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ==='
23
echo
24
25
# Prep the images
26
+# VPC rounds image sizes to a specific geometry, force a specific size.
27
+if [ "$IMGFMT" = "vpc" ]; then
28
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
29
+fi
30
_make_test_img 4G
31
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
32
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
33
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
34
index XXXXXXX..XXXXXXX 100644
35
--- a/tests/qemu-iotests/common.filter
36
+++ b/tests/qemu-iotests/common.filter
37
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
38
-e "s# log_size=[0-9]\\+##g" \
39
-e "s# refcount_bits=[0-9]\\+##g" \
40
-e "s# key-secret=[a-zA-Z0-9]\\+##g" \
41
- -e "s# iter-time=[0-9]\\+##g"
42
+ -e "s# iter-time=[0-9]\\+##g" \
43
+ -e "s# force_size=\\(on\\|off\\)##g"
44
}
45
46
_filter_img_info()
47
--
48
2.13.6
49
50
diff view generated by jsdifflib
1
bdrv_invalidate_cache_all() assumes that all nodes in a given subtree
1
This change separates bdrv_drain_invoke(), which calls the BlockDriver
2
are either active or inactive when it starts. Therefore, as soon as it
2
drain callbacks, from bdrv_drain_recurse(). Instead, the function
3
arrives at an already active node, it stops.
3
performs its own recursion now.
4
4
5
However, this assumption is wrong. For example, it's possible to take a
5
One reason for this is that bdrv_drain_recurse() can be called multiple
6
snapshot of an inactive node, which results in an active overlay over an
6
times by bdrv_drain_all_begin(), but the callbacks may only be called
7
inactive backing file. The active overlay is probably also the root node
7
once. The separation is necessary to fix this bug.
8
of an inactive BlockBackend (blk->disable_perm == true).
9
8
10
In this case, bdrv_invalidate_cache_all() does not need to do anything
9
The other reason is that we intend to go to a model where we call all
11
to activate the overlay node, but it still needs to recurse into the
10
driver callbacks first, and only then start polling. This is not fully
12
children and the parents to make sure that after returning success,
11
achieved yet with this patch, as bdrv_drain_invoke() contains a
13
really everything is activated.
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.
14
15
15
Cc: qemu-stable@nongnu.org
16
Cc: qemu-stable@nongnu.org
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
18
---
19
---
19
block.c | 50 ++++++++++++++++++++++++--------------------------
20
block/io.c | 14 +++++++++++---
20
1 file changed, 24 insertions(+), 26 deletions(-)
21
1 file changed, 11 insertions(+), 3 deletions(-)
21
22
22
diff --git a/block.c b/block.c
23
diff --git a/block/io.c b/block/io.c
23
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
24
--- a/block.c
25
--- a/block/io.c
25
+++ b/block.c
26
+++ b/block/io.c
26
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
27
return;
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);
28
}
61
}
29
62
30
- if (!(bs->open_flags & BDRV_O_INACTIVE)) {
63
+ bdrv_drain_invoke(bs, true);
31
- return;
64
bdrv_drain_recurse(bs, true);
32
- }
65
}
33
-
66
34
QLIST_FOREACH(child, &bs->children, next) {
67
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
35
bdrv_co_invalidate_cache(child->bs, &local_err);
36
if (local_err) {
37
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
38
* just keep the extended permissions for the next time that an activation
39
* of the image is tried.
40
*/
41
- bs->open_flags &= ~BDRV_O_INACTIVE;
42
- bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
43
- ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, &local_err);
44
- if (ret < 0) {
45
- bs->open_flags |= BDRV_O_INACTIVE;
46
- error_propagate(errp, local_err);
47
- return;
48
- }
49
- bdrv_set_perm(bs, perm, shared_perm);
50
-
51
- if (bs->drv->bdrv_co_invalidate_cache) {
52
- bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
53
- if (local_err) {
54
+ if (bs->open_flags & BDRV_O_INACTIVE) {
55
+ bs->open_flags &= ~BDRV_O_INACTIVE;
56
+ bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
57
+ ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, &local_err);
58
+ if (ret < 0) {
59
bs->open_flags |= BDRV_O_INACTIVE;
60
error_propagate(errp, local_err);
61
return;
62
}
63
- }
64
+ bdrv_set_perm(bs, perm, shared_perm);
65
66
- FOR_EACH_DIRTY_BITMAP(bs, bm) {
67
- bdrv_dirty_bitmap_skip_store(bm, false);
68
- }
69
+ if (bs->drv->bdrv_co_invalidate_cache) {
70
+ bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
71
+ if (local_err) {
72
+ bs->open_flags |= BDRV_O_INACTIVE;
73
+ error_propagate(errp, local_err);
74
+ return;
75
+ }
76
+ }
77
78
- ret = refresh_total_sectors(bs, bs->total_sectors);
79
- if (ret < 0) {
80
- bs->open_flags |= BDRV_O_INACTIVE;
81
- error_setg_errno(errp, -ret, "Could not refresh total sector count");
82
- return;
83
+ FOR_EACH_DIRTY_BITMAP(bs, bm) {
84
+ bdrv_dirty_bitmap_skip_store(bm, false);
85
+ }
86
+
87
+ ret = refresh_total_sectors(bs, bs->total_sectors);
88
+ if (ret < 0) {
89
+ bs->open_flags |= BDRV_O_INACTIVE;
90
+ error_setg_errno(errp, -ret, "Could not refresh total sector count");
91
+ return;
92
+ }
93
}
68
}
94
69
95
QLIST_FOREACH(parent, &bs->parents, next_parent) {
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
}
96
--
92
--
97
2.20.1
93
2.13.6
98
94
99
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
This tests creating an external snapshot with VM state (which results in
1
This adds a test case that the BlockDriver callbacks for drain are
2
an active overlay over an inactive backing file, which is also the root
2
called in bdrv_drained_all_begin/end(), and that both of them are called
3
node of an inactive BlockBackend), re-activating the images and
3
exactly once.
4
performing some operations to test that the re-activation worked as
5
intended.
6
4
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
8
---
9
tests/qemu-iotests/280 | 83 ++++++++++++++++++++++++++++++++++++++
9
tests/test-bdrv-drain.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/280.out | 50 +++++++++++++++++++++++
10
tests/Makefile.include | 2 +
11
tests/qemu-iotests/group | 1 +
11
2 files changed, 139 insertions(+)
12
3 files changed, 134 insertions(+)
12
create mode 100644 tests/test-bdrv-drain.c
13
create mode 100755 tests/qemu-iotests/280
14
create mode 100644 tests/qemu-iotests/280.out
15
13
16
diff --git a/tests/qemu-iotests/280 b/tests/qemu-iotests/280
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
17
new file mode 100755
18
index XXXXXXX..XXXXXXX
19
--- /dev/null
20
+++ b/tests/qemu-iotests/280
21
@@ -XXX,XX +XXX,XX @@
22
+#!/usr/bin/env python
23
+#
24
+# Copyright (C) 2019 Red Hat, Inc.
25
+#
26
+# This program is free software; you can redistribute it and/or modify
27
+# it under the terms of the GNU General Public License as published by
28
+# the Free Software Foundation; either version 2 of the License, or
29
+# (at your option) any later version.
30
+#
31
+# This program is distributed in the hope that it will be useful,
32
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
33
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
+# GNU General Public License for more details.
35
+#
36
+# You should have received a copy of the GNU General Public License
37
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
38
+#
39
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
40
+#
41
+# Test migration to file for taking an external snapshot with VM state.
42
+
43
+import iotests
44
+import os
45
+
46
+iotests.verify_image_format(supported_fmts=['qcow2'])
47
+iotests.verify_protocol(supported=['file'])
48
+iotests.verify_platform(['linux'])
49
+
50
+with iotests.FilePath('base') as base_path , \
51
+ iotests.FilePath('top') as top_path, \
52
+ iotests.VM() as vm:
53
+
54
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base_path, '64M')
55
+
56
+ iotests.log('=== Launch VM ===')
57
+ vm.add_object('iothread,id=iothread0')
58
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % (base_path))
59
+ vm.add_blockdev('%s,file=base-file,node-name=base-fmt' % (iotests.imgfmt))
60
+ vm.add_device('virtio-blk,drive=base-fmt,iothread=iothread0,id=vda')
61
+ vm.launch()
62
+
63
+ vm.enable_migration_events('VM')
64
+
65
+ iotests.log('\n=== Migrate to file ===')
66
+ vm.qmp_log('migrate', uri='exec:cat > /dev/null')
67
+
68
+ with iotests.Timeout(3, 'Migration does not complete'):
69
+ vm.wait_migration()
70
+
71
+ iotests.log('\nVM is now stopped:')
72
+ iotests.log(vm.qmp('query-migrate')['return']['status'])
73
+ vm.qmp_log('query-status')
74
+
75
+ iotests.log('\n=== Create a snapshot of the disk image ===')
76
+ vm.blockdev_create({
77
+ 'driver': 'file',
78
+ 'filename': top_path,
79
+ 'size': 0,
80
+ })
81
+ vm.qmp_log('blockdev-add', node_name='top-file',
82
+ driver='file', filename=top_path,
83
+ filters=[iotests.filter_qmp_testfiles])
84
+
85
+ vm.blockdev_create({
86
+ 'driver': iotests.imgfmt,
87
+ 'file': 'top-file',
88
+ 'size': 1024 * 1024,
89
+ })
90
+ vm.qmp_log('blockdev-add', node_name='top-fmt',
91
+ driver=iotests.imgfmt, file='top-file')
92
+
93
+ vm.qmp_log('blockdev-snapshot', node='base-fmt', overlay='top-fmt')
94
+
95
+ iotests.log('\n=== Resume the VM and simulate a write request ===')
96
+ vm.qmp_log('cont')
97
+ iotests.log(vm.hmp_qemu_io('-d vda/virtio-backend', 'write 4k 4k'))
98
+
99
+ iotests.log('\n=== Commit it to the backing file ===')
100
+ result = vm.qmp_log('block-commit', job_id='job0', auto_dismiss=False,
101
+ device='top-fmt', top_node='top-fmt',
102
+ filters=[iotests.filter_qmp_testfiles])
103
+ if 'return' in result:
104
+ vm.run_job('job0')
105
diff --git a/tests/qemu-iotests/280.out b/tests/qemu-iotests/280.out
106
new file mode 100644
15
new file mode 100644
107
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
108
--- /dev/null
17
--- /dev/null
109
+++ b/tests/qemu-iotests/280.out
18
+++ b/tests/test-bdrv-drain.c
110
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
111
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
20
+/*
21
+ * Block node draining tests
22
+ *
23
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
24
+ *
25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
26
+ * of this software and associated documentation files (the "Software"), to deal
27
+ * in the Software without restriction, including without limitation the rights
28
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29
+ * copies of the Software, and to permit persons to whom the Software is
30
+ * furnished to do so, subject to the following conditions:
31
+ *
32
+ * The above copyright notice and this permission notice shall be included in
33
+ * all copies or substantial portions of the Software.
34
+ *
35
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41
+ * THE SOFTWARE.
42
+ */
112
+
43
+
113
+=== Launch VM ===
44
+#include "qemu/osdep.h"
114
+Enabling migration QMP events on VM...
45
+#include "block/block.h"
115
+{"return": {}}
46
+#include "sysemu/block-backend.h"
47
+#include "qapi/error.h"
116
+
48
+
117
+=== Migrate to file ===
49
+typedef struct BDRVTestState {
118
+{"execute": "migrate", "arguments": {"uri": "exec:cat > /dev/null"}}
50
+ int drain_count;
119
+{"return": {}}
51
+} BDRVTestState;
120
+{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
121
+{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
122
+{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
123
+
52
+
124
+VM is now stopped:
53
+static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
125
+completed
54
+{
126
+{"execute": "query-status", "arguments": {}}
55
+ BDRVTestState *s = bs->opaque;
127
+{"return": {"running": false, "singlestep": false, "status": "postmigrate"}}
56
+ s->drain_count++;
57
+}
128
+
58
+
129
+=== Create a snapshot of the disk image ===
59
+static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
130
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-top", "size": 0}}}
60
+{
131
+{"return": {}}
61
+ BDRVTestState *s = bs->opaque;
132
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
62
+ s->drain_count--;
133
+{"return": {}}
63
+}
134
+
64
+
135
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-top", "node-name": "top-file"}}
65
+static void bdrv_test_close(BlockDriverState *bs)
136
+{"return": {}}
66
+{
137
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "top-file", "size": 1048576}}}
67
+ BDRVTestState *s = bs->opaque;
138
+{"return": {}}
68
+ g_assert_cmpint(s->drain_count, >, 0);
139
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
69
+}
140
+{"return": {}}
141
+
70
+
142
+{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": "top-file", "node-name": "top-fmt"}}
71
+static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
143
+{"return": {}}
72
+ uint64_t offset, uint64_t bytes,
144
+{"execute": "blockdev-snapshot", "arguments": {"node": "base-fmt", "overlay": "top-fmt"}}
73
+ QEMUIOVector *qiov, int flags)
145
+{"return": {}}
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);
146
+
80
+
147
+=== Resume the VM and simulate a write request ===
81
+ return 0;
148
+{"execute": "cont", "arguments": {}}
82
+}
149
+{"return": {}}
150
+{"return": ""}
151
+
83
+
152
+=== Commit it to the backing file ===
84
+static BlockDriver bdrv_test = {
153
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "device": "top-fmt", "job-id": "job0", "top-node": "top-fmt"}}
85
+ .format_name = "test",
154
+{"return": {}}
86
+ .instance_size = sizeof(BDRVTestState),
155
+{"execute": "job-complete", "arguments": {"id": "job0"}}
87
+
156
+{"return": {}}
88
+ .bdrv_close = bdrv_test_close,
157
+{"data": {"device": "job0", "len": 65536, "offset": 65536, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
89
+ .bdrv_co_preadv = bdrv_test_co_preadv,
158
+{"data": {"device": "job0", "len": 65536, "offset": 65536, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
90
+
159
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
91
+ .bdrv_co_drain_begin = bdrv_test_co_drain_begin,
160
+{"return": {}}
92
+ .bdrv_co_drain_end = bdrv_test_co_drain_end,
161
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
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
162
index XXXXXXX..XXXXXXX 100644
158
index XXXXXXX..XXXXXXX 100644
163
--- a/tests/qemu-iotests/group
159
--- a/tests/Makefile.include
164
+++ b/tests/qemu-iotests/group
160
+++ b/tests/Makefile.include
165
@@ -XXX,XX +XXX,XX @@
161
@@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c
166
273 backing quick
162
gcov-files-test-hbitmap-y = util/hbitmap.c
167
277 rw quick
163
check-unit-y += tests/test-hbitmap$(EXESUF)
168
279 rw backing quick
164
gcov-files-test-hbitmap-y = blockjob.c
169
+280 rw migration 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)
170
--
177
--
171
2.20.1
178
2.13.6
172
179
173
180
diff view generated by jsdifflib
1
Automatically complete jobs that have a 'ready' state and need an
1
Now that the bdrv_drain_invoke() calls are pulled up to the callers of
2
explicit job-complete. Without this, run_job() would hang for such
2
bdrv_drain_recurse(), the 'begin' parameter isn't needed any more.
3
jobs.
4
3
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
6
---
11
tests/qemu-iotests/iotests.py | 2 ++
7
block/io.c | 12 ++++++------
12
1 file changed, 2 insertions(+)
8
1 file changed, 6 insertions(+), 6 deletions(-)
13
9
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
10
diff --git a/block/io.c b/block/io.c
15
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/iotests.py
12
--- a/block/io.c
17
+++ b/tests/qemu-iotests/iotests.py
13
+++ b/block/io.c
18
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
14
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
19
error = j['error']
15
}
20
if use_log:
16
}
21
log('Job failed: %s' % (j['error']))
17
22
+ elif status == 'ready':
18
-static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
23
+ self.qmp_log('job-complete', id=job)
19
+static bool bdrv_drain_recurse(BlockDriverState *bs)
24
elif status == 'pending' and not auto_finalize:
20
{
25
if pre_finalize:
21
BdrvChild *child, *tmp;
26
pre_finalize()
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
27
--
68
--
28
2.20.1
69
2.13.6
29
70
30
71
diff view generated by jsdifflib
1
run_job() accepts a wait parameter for a timeout, but it doesn't
1
The device is drained, so there is no point in waiting for requests at
2
actually use it. The only thing that is missing is passing it to
2
the end of the drained section. Remove the bdrv_drain_recurse() calls
3
events_wait(), so do that now.
3
there.
4
5
The bdrv_drain_recurse() calls were introduced in commit 481cad48e5e
6
in order to call the .bdrv_co_drain_end() driver callback. This is now
7
done by a separate bdrv_drain_invoke() call.
4
8
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
12
---
11
tests/qemu-iotests/iotests.py | 2 +-
13
block/io.c | 2 --
12
1 file changed, 1 insertion(+), 1 deletion(-)
14
1 file changed, 2 deletions(-)
13
15
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
16
diff --git a/block/io.c b/block/io.c
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/iotests.py
18
--- a/block/io.c
17
+++ b/tests/qemu-iotests/iotests.py
19
+++ b/block/io.c
18
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
20
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
19
]
21
20
error = None
22
bdrv_parent_drained_end(bs);
21
while True:
23
bdrv_drain_invoke(bs, false);
22
- ev = filter_qmp_event(self.events_wait(events))
24
- bdrv_drain_recurse(bs);
23
+ ev = filter_qmp_event(self.events_wait(events, timeout=wait))
25
aio_enable_external(bdrv_get_aio_context(bs));
24
if ev['event'] != 'JOB_STATUS_CHANGE':
26
}
25
if use_log:
27
26
log(ev)
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
27
--
36
--
28
2.20.1
37
2.13.6
29
38
30
39
diff view generated by jsdifflib
1
Add a function that runs qemu-io and logs the output with the
1
Drain requests are propagated to child nodes, parent nodes and directly
2
appropriate filters applied.
2
to the AioContext. The order in which this happened was different
3
between all combinations of drain/drain_all and begin/end.
4
5
The correct order is to keep children only drained when their parents
6
are also drained. This means that at the start of a drained section, the
7
AioContext needs to be drained first, the parents second and only then
8
the children. The correct order for the end of a drained section is the
9
opposite.
10
11
This patch changes the three other functions to follow the example of
12
bdrv_drained_begin(), which is the only one that got it right.
3
13
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
16
---
10
tests/qemu-iotests/iotests.py | 5 +++++
17
block/io.c | 12 ++++++++----
11
1 file changed, 5 insertions(+)
18
1 file changed, 8 insertions(+), 4 deletions(-)
12
19
13
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
20
diff --git a/block/io.c b/block/io.c
14
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/iotests.py
22
--- a/block/io.c
16
+++ b/tests/qemu-iotests/iotests.py
23
+++ b/block/io.c
17
@@ -XXX,XX +XXX,XX @@ def qemu_io(*args):
24
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
18
sys.stderr.write('qemu-io received signal %i: %s\n' % (-exitcode, ' '.join(args)))
25
return;
19
return subp.communicate()[0]
26
}
20
27
21
+def qemu_io_log(*args):
28
+ /* Stop things in parent-to-child order */
22
+ result = qemu_io(*args)
29
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
23
+ log(result, filters=[filter_testfiles, filter_qemu_io])
30
aio_disable_external(bdrv_get_aio_context(bs));
24
+ return result
31
bdrv_parent_drained_begin(bs);
25
+
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
26
def qemu_io_silent(*args):
33
return;
27
'''Run qemu-io and return the exit code, suppressing stdout'''
34
}
28
args = qemu_io_args + list(args)
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
29
--
69
--
30
2.20.1
70
2.13.6
31
71
32
72
diff view generated by jsdifflib
1
In order to issue requests on an existing BlockBackend with the
1
Commit 15afd94a047 added code to acquire and release the AioContext in
2
'qemu-io' HMP command, allow specifying the BlockBackend not only with a
2
qemuio_command(). This means that the lock is taken twice now in the
3
BlockBackend name, but also with a qdev ID/QOM path for a device that
3
call path from hmp_qemu_io(). This causes BDRV_POLL_WHILE() to hang for
4
owns the (possibly anonymous) BlockBackend.
4
any requests issued to nodes in a non-mainloop AioContext.
5
5
6
Because qdev names could be conflicting with BlockBackend and node
6
Dropping the first locking from hmp_qemu_io() fixes the problem.
7
names, introduce a -d option to explicitly address a device. If the
8
option is not given, a BlockBackend or a node is addressed.
9
7
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
10
---
12
monitor/hmp-cmds.c | 28 ++++++++++++++++++----------
11
hmp.c | 6 ------
13
hmp-commands.hx | 8 +++++---
12
1 file changed, 6 deletions(-)
14
2 files changed, 23 insertions(+), 13 deletions(-)
15
13
16
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
14
diff --git a/hmp.c b/hmp.c
17
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
18
--- a/monitor/hmp-cmds.c
16
--- a/hmp.c
19
+++ b/monitor/hmp-cmds.c
17
+++ b/hmp.c
20
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
18
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
21
{
19
{
22
BlockBackend *blk;
20
BlockBackend *blk;
23
BlockBackend *local_blk = NULL;
21
BlockBackend *local_blk = NULL;
24
+ bool qdev = qdict_get_try_bool(qdict, "qdev", false);
22
- AioContext *aio_context;
25
const char* device = qdict_get_str(qdict, "device");
23
const char* device = qdict_get_str(qdict, "device");
26
const char* command = qdict_get_str(qdict, "command");
24
const char* command = qdict_get_str(qdict, "command");
27
Error *err = NULL;
25
Error *err = NULL;
28
int ret;
26
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
29
30
- blk = blk_by_name(device);
31
- if (!blk) {
32
- BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
33
- if (bs) {
34
- blk = local_blk = blk_new(bdrv_get_aio_context(bs),
35
- 0, BLK_PERM_ALL);
36
- ret = blk_insert_bs(blk, bs, &err);
37
- if (ret < 0) {
38
+ if (qdev) {
39
+ blk = blk_by_qdev_id(device, &err);
40
+ if (!blk) {
41
+ goto fail;
42
+ }
43
+ } else {
44
+ blk = blk_by_name(device);
45
+ if (!blk) {
46
+ BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
47
+ if (bs) {
48
+ blk = local_blk = blk_new(bdrv_get_aio_context(bs),
49
+ 0, BLK_PERM_ALL);
50
+ ret = blk_insert_bs(blk, bs, &err);
51
+ if (ret < 0) {
52
+ goto fail;
53
+ }
54
+ } else {
55
goto fail;
56
}
57
- } else {
58
- goto fail;
59
}
27
}
60
}
28
}
61
29
62
diff --git a/hmp-commands.hx b/hmp-commands.hx
30
- aio_context = blk_get_aio_context(blk);
63
index XXXXXXX..XXXXXXX 100644
31
- aio_context_acquire(aio_context);
64
--- a/hmp-commands.hx
32
-
65
+++ b/hmp-commands.hx
33
/*
66
@@ -XXX,XX +XXX,XX @@ ETEXI
34
* Notably absent: Proper permission management. This is sad, but it seems
67
35
* almost impossible to achieve without changing the semantics and thereby
68
{
36
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
69
.name = "qemu-io",
37
*/
70
- .args_type = "device:B,command:s",
38
qemuio_command(blk, command);
71
- .params = "[device] \"[command]\"",
39
72
- .help = "run a qemu-io command on a block device",
40
- aio_context_release(aio_context);
73
+ .args_type = "qdev:-d,device:B,command:s",
41
-
74
+ .params = "[-d] [device] \"[command]\"",
42
fail:
75
+ .help = "run a qemu-io command on a block device\n\t\t\t"
43
blk_unref(local_blk);
76
+ "-d: [device] is a device ID rather than a "
44
hmp_handle_error(mon, &err);
77
+ "drive ID or node name",
78
.cmd = hmp_qemu_io,
79
},
80
81
--
45
--
82
2.20.1
46
2.13.6
83
47
84
48
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
2
2
3
There's a couple of places left in the qcow2 code that still do the
3
Since bdrv_co_preadv does all neccessary checks including
4
calculation manually, so let's replace them.
4
reading after the end of the backing file, avoid duplication
5
of verification before bdrv_co_preadv call.
5
6
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
11
---
10
block/qcow2.c | 8 +++-----
12
block/qcow2.h | 3 ---
11
1 file changed, 3 insertions(+), 5 deletions(-)
13
block/qcow2.c | 51 ++++++++-------------------------------------------
14
2 files changed, 8 insertions(+), 46 deletions(-)
12
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);
13
diff --git a/block/qcow2.c b/block/qcow2.c
30
diff --git a/block/qcow2.c b/block/qcow2.c
14
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qcow2.c
32
--- a/block/qcow2.c
16
+++ b/block/qcow2.c
33
+++ b/block/qcow2.c
17
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
34
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
18
return -EINVAL;
35
return status;
19
}
36
}
20
37
21
- if (bitmaps_ext.bitmap_directory_offset & (s->cluster_size - 1)) {
38
-/* handle reading after the end of the backing file */
22
+ if (offset_into_cluster(s, bitmaps_ext.bitmap_directory_offset)) {
39
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
23
error_setg(errp, "bitmaps_ext: "
40
- int64_t offset, int bytes)
24
"invalid bitmap directory offset");
41
-{
25
return -EINVAL;
42
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
26
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
43
- int n1;
44
-
45
- if ((offset + bytes) <= bs_size) {
46
- return bytes;
47
- }
48
-
49
- if (offset >= bs_size) {
50
- n1 = 0;
51
- } else {
52
- n1 = bs_size - offset;
53
- }
54
-
55
- qemu_iovec_memset(qiov, n1, 0, bytes - n1);
56
-
57
- return n1;
58
-}
59
-
60
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
61
uint64_t bytes, QEMUIOVector *qiov,
62
int flags)
27
{
63
{
28
BDRVQcow2State *s = bs->opaque;
64
BDRVQcow2State *s = bs->opaque;
29
uint64_t cluster_offset;
65
- int offset_in_cluster, n1;
30
- int index_in_cluster, ret;
66
+ int offset_in_cluster;
31
unsigned int bytes;
67
int ret;
32
- int status = 0;
68
unsigned int cur_bytes; /* number of bytes in current iteration */
33
+ int ret, status = 0;
69
uint64_t cluster_offset = 0;
34
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
35
qemu_co_mutex_lock(&s->lock);
71
case QCOW2_CLUSTER_UNALLOCATED:
36
72
37
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
73
if (bs->backing) {
38
74
- /* read from the base image */
39
if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) &&
75
- n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
40
!s->crypto) {
76
- offset, cur_bytes);
41
- index_in_cluster = offset & (s->cluster_size - 1);
77
- if (n1 > 0) {
42
- *map = cluster_offset | index_in_cluster;
78
- QEMUIOVector local_qiov;
43
+ *map = cluster_offset | offset_into_cluster(s, offset);
79
-
44
*file = s->data_file->bs;
80
- qemu_iovec_init(&local_qiov, hd_qiov.niov);
45
status |= BDRV_BLOCK_OFFSET_VALID;
81
- qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1);
46
}
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 */
47
--
104
--
48
2.20.1
105
2.13.6
49
106
50
107
diff view generated by jsdifflib
1
From: Daniel P. Berrangé <berrange@redhat.com>
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().
2
5
3
Mention that this is a PCI device address & give the format it is
6
Document this problem so that we won't accidentally mark the command
4
expected in. Also mention that it must be first unbound from any
7
stable without having addressed it.
5
host kernel driver.
6
8
7
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
---
11
---
12
qapi/block-core.json | 6 +++++-
12
qapi/block-core.json | 4 ++++
13
1 file changed, 5 insertions(+), 1 deletion(-)
13
1 file changed, 4 insertions(+)
14
14
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
17
--- a/qapi/block-core.json
18
+++ b/qapi/block-core.json
18
+++ b/qapi/block-core.json
19
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
20
# does not support all kinds of operations, all kinds of children, nor
21
# all block drivers.
20
#
22
#
21
# Driver specific block device options for the NVMe backend.
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.
22
#
29
#
23
-# @device: controller address of the NVMe device.
24
+# @device: PCI controller address of the NVMe device in
25
+# format hhhh:bb:ss.f (host:bus:slot.function)
26
# @namespace: namespace number of the device, starting from 1.
27
#
28
+# Note that the PCI @device must have been unbound from any host
29
+# kernel driver before instructing QEMU to add the blockdev.
30
+#
31
# Since: 2.12
32
##
33
{ 'struct': 'BlockdevOptionsNVMe',
34
--
30
--
35
2.20.1
31
2.13.6
36
32
37
33
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Doug Gale <doug16k@gmail.com>
2
2
3
Somehow I wrote not full path to the file. Fix that.
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.
4
7
5
Also, while being here, rearrange entries, so that includes go first,
8
Signed-off-by: Doug Gale <doug16k@gmail.com>
6
then block, than migration, than util.
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Fixes: 052db8e71444d
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
---
12
MAINTAINERS | 6 +++---
13
hw/block/nvme.c | 349 ++++++++++++++++++++++++++++++++++++++++++--------
13
1 file changed, 3 insertions(+), 3 deletions(-)
14
hw/block/trace-events | 93 ++++++++++++++
15
2 files changed, 390 insertions(+), 52 deletions(-)
14
16
15
diff --git a/MAINTAINERS b/MAINTAINERS
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/MAINTAINERS
19
--- a/hw/block/nvme.c
18
+++ b/MAINTAINERS
20
+++ b/hw/block/nvme.c
19
@@ -XXX,XX +XXX,XX @@ M: John Snow <jsnow@redhat.com>
21
@@ -XXX,XX +XXX,XX @@
20
R: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
22
#include "qapi/visitor.h"
21
L: qemu-block@nongnu.org
23
#include "sysemu/block-backend.h"
22
S: Supported
24
23
-F: util/hbitmap.c
25
+#include "qemu/log.h"
24
-F: block/dirty-bitmap.c
26
+#include "trace.h"
25
F: include/qemu/hbitmap.h
27
#include "nvme.h"
26
F: include/block/dirty-bitmap.h
28
27
-F: qcow2-bitmap.c
29
+#define NVME_GUEST_ERR(trace, fmt, ...) \
28
+F: block/dirty-bitmap.c
30
+ do { \
29
+F: block/qcow2-bitmap.c
31
+ (trace_##trace)(__VA_ARGS__); \
30
F: migration/block-dirty-bitmap.c
32
+ qemu_log_mask(LOG_GUEST_ERROR, #trace \
31
+F: util/hbitmap.c
33
+ " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
32
F: tests/test-hbitmap.c
34
+ } while (0)
33
F: docs/interop/bitmaps.rst
35
+
34
T: git https://github.com/jnsnow/qemu.git bitmaps
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"
35
--
784
--
36
2.20.1
785
2.13.6
37
786
38
787
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
There is no $SOCKDIR, only $SOCK_DIR.
3
Management tools create overlays of running guests with qemu-img:
4
4
5
Fixes: f3923a72f199b2c63747a7032db74730546f55c6
5
$ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
but this doesn't work anymore due to image locking:
8
9
qemu-img: /overlay/image.qcow2: Failed to get shared "write" lock
10
Is another process using the image?
11
Could not open backing image to determine size.
12
Use the force share option to allow this use case again.
13
14
Cc: qemu-stable@nongnu.org
15
Signed-off-by: Fam Zheng <famz@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
18
---
10
tests/qemu-iotests/common.rc | 3 ++-
19
block.c | 3 ++-
11
1 file changed, 2 insertions(+), 1 deletion(-)
20
1 file changed, 2 insertions(+), 1 deletion(-)
12
21
13
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
22
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/common.rc
24
--- a/block.c
16
+++ b/tests/qemu-iotests/common.rc
25
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ if [ "$IMGOPTSSYNTAX" = "true" ]; then
26
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
18
TEST_IMG="$DRIVER,file.filename=$TEST_DIR/t.$IMGFMT"
27
back_flags = flags;
19
elif [ "$IMGPROTO" = "nbd" ]; then
28
back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
20
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
29
21
- TEST_IMG="$DRIVER,file.driver=nbd,file.type=unix,file.path=$SOCKDIR/nbd"
30
+ backing_options = qdict_new();
22
+ TEST_IMG="$DRIVER,file.driver=nbd,file.type=unix"
31
if (backing_fmt) {
23
+ TEST_IMG="$TEST_IMG,file.path=$SOCK_DIR/nbd"
32
- backing_options = qdict_new();
24
elif [ "$IMGPROTO" = "ssh" ]; then
33
qdict_put_str(backing_options, "driver", backing_fmt);
25
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
34
}
26
TEST_IMG="$DRIVER,file.driver=ssh,file.host=127.0.0.1,file.path=$TEST_IMG_FILE"
35
+ qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true);
36
37
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
38
&local_err);
27
--
39
--
28
2.20.1
40
2.13.6
29
41
30
42
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Test 051 should be skipped if nbd is not available, and 267 should
3
It's not working anymore since QEMU v1.3.0 - time to remove it now.
4
be skipped if copy-on-read is not enabled.
5
4
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
5
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: John Snow <jsnow@redhat.com>
7
Reviewed-by: Markus Armbruster <armbru@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
9
---
10
tests/qemu-iotests/051 | 1 +
10
blockdev.c | 11 -----------
11
tests/qemu-iotests/267 | 1 +
11
qemu-doc.texi | 6 ------
12
2 files changed, 2 insertions(+)
12
2 files changed, 17 deletions(-)
13
13
14
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
14
diff --git a/blockdev.c b/blockdev.c
15
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/051
16
--- a/blockdev.c
17
+++ b/tests/qemu-iotests/051
17
+++ b/blockdev.c
18
@@ -XXX,XX +XXX,XX @@ _supported_proto file
18
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
19
# A compat=0.10 image is created in this test which does not support anything
19
.type = QEMU_OPT_STRING,
20
# other than refcount_bits=16
20
.help = "chs translation (auto, lba, none)",
21
_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
21
},{
22
+_require_drivers nbd
22
- .name = "boot",
23
23
- .type = QEMU_OPT_BOOL,
24
do_run_qemu()
24
- .help = "(deprecated, ignored)",
25
{
25
- },{
26
diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267
26
.name = "addr",
27
index XXXXXXX..XXXXXXX 100755
27
.type = QEMU_OPT_STRING,
28
--- a/tests/qemu-iotests/267
28
.help = "pci address (virtio only)",
29
+++ b/tests/qemu-iotests/267
29
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
30
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
30
goto fail;
31
_supported_fmt qcow2
31
}
32
_supported_proto file
32
33
_supported_os Linux
33
- /* Deprecated option boot=[on|off] */
34
+_require_drivers copy-on-read
34
- if (qemu_opt_get(legacy_opts, "boot") != NULL) {
35
35
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
36
# Internal snapshots are (currently) impossible with refcount_bits=1
36
- "ignored. Future versions will reject this parameter. Please "
37
_unsupported_imgopts 'refcount_bits=1[^0-9]'
37
- "update your scripts.\n");
38
- }
39
-
40
/* Other deprecated options */
41
if (!qtest_enabled()) {
42
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
43
diff --git a/qemu-doc.texi b/qemu-doc.texi
44
index XXXXXXX..XXXXXXX 100644
45
--- a/qemu-doc.texi
46
+++ b/qemu-doc.texi
47
@@ -XXX,XX +XXX,XX @@ deprecated.
48
49
@section System emulator command line arguments
50
51
-@subsection -drive boot=on|off (since 1.3.0)
52
-
53
-The ``boot=on|off'' option to the ``-drive'' argument is
54
-ignored. Applications should use the ``bootindex=N'' parameter
55
-to set an absolute ordering between devices instead.
56
-
57
@subsection -tdf (since 1.3.0)
58
59
The ``-tdf'' argument is ignored. The behaviour implemented
38
--
60
--
39
2.20.1
61
2.13.6
40
62
41
63
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Test 060 fails in the arm64, s390x and ppc64le LXD containers on Travis
3
It's been marked as deprecated since QEMU v2.10.0, and so far nobody
4
(which we will hopefully enable in our CI soon). These containers
4
complained that we should keep it, so let's remove this legacy option
5
apparently do not allow large files to be created. The repair process
5
now to simplify the code quite a bit.
6
in test 060 creates a file of 64 GiB, so test first whether such large
7
files are possible and skip the test if that's not the case.
8
6
9
Signed-off-by: Thomas Huth <thuth@redhat.com>
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>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
11
---
12
tests/qemu-iotests/060 | 3 +++
12
vl.c | 86 ++-------------------------------------------------------
13
1 file changed, 3 insertions(+)
13
qemu-doc.texi | 8 ------
14
14
qemu-options.hx | 19 ++-----------
15
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
15
3 files changed, 4 insertions(+), 109 deletions(-)
16
index XXXXXXX..XXXXXXX 100755
16
17
--- a/tests/qemu-iotests/060
17
diff --git a/vl.c b/vl.c
18
+++ b/tests/qemu-iotests/060
18
index XXXXXXX..XXXXXXX 100644
19
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2
19
--- a/vl.c
20
_supported_proto file
20
+++ b/vl.c
21
_supported_os Linux
21
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
22
22
const char *boot_order = NULL;
23
+# The repair process will create a large file - so check for availability first
23
const char *boot_once = NULL;
24
+_require_large_file 64G
24
DisplayState *ds;
25
+
25
- int cyls, heads, secs, translation;
26
rt_offset=65536 # 0x10000 (XXX: just an assumption)
26
QemuOpts *opts, *machine_opts;
27
rb_offset=131072 # 0x20000 (XXX: just an assumption)
27
- QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL;
28
l1_offset=196608 # 0x30000 (XXX: just an assumption)
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"
29
--
199
--
30
2.20.1
200
2.13.6
31
201
32
202
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Test 079 fails in the arm64, s390x and ppc64le LXD containers on Travis
3
Looks like we forgot to announce the deprecation of these options in
4
(which we will hopefully enable in our CI soon). These containers
4
the corresponding chapter of the qemu-doc text, so let's do that now.
5
apparently do not allow large files to be created. Test 079 tries to
6
create a 4G sparse file, which is apparently already too big for these
7
containers, so check first whether we can really create such files before
8
executing the test.
9
5
10
Signed-off-by: Thomas Huth <thuth@redhat.com>
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
10
---
13
tests/qemu-iotests/079 | 3 +++
11
qemu-doc.texi | 15 +++++++++++++++
14
1 file changed, 3 insertions(+)
12
1 file changed, 15 insertions(+)
15
13
16
diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079
14
diff --git a/qemu-doc.texi b/qemu-doc.texi
17
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/079
16
--- a/qemu-doc.texi
19
+++ b/tests/qemu-iotests/079
17
+++ b/qemu-doc.texi
20
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
18
@@ -XXX,XX +XXX,XX @@ longer be directly supported in QEMU.
21
_supported_fmt qcow2
19
The ``-drive if=scsi'' argument is replaced by the the
22
_supported_proto file nfs
20
``-device BUS-TYPE'' argument combined with ``-drive if=none''.
23
21
24
+# Some containers (e.g. non-x86 on Travis) do not allow large files
22
+@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
25
+_require_large_file 4G
26
+
23
+
27
echo "=== Check option preallocation and cluster_size ==="
24
+The drive geometry arguments are replaced by the the geometry arguments
28
echo
25
+that can be specified with the ``-device'' parameter.
29
cluster_sizes="16384 32768 65536 131072 262144 524288 1048576 2097152 4194304"
26
+
27
+@subsection -drive serial=... (since 2.10.0)
28
+
29
+The drive serial argument is replaced by the the serial argument
30
+that can be specified with the ``-device'' parameter.
31
+
32
+@subsection -drive addr=... (since 2.10.0)
33
+
34
+The drive addr argument is replaced by the the addr argument
35
+that can be specified with the ``-device'' parameter.
36
+
37
@subsection -net dump (since 2.10.0)
38
39
The ``--net dump'' argument is now replaced with the
30
--
40
--
31
2.20.1
41
2.13.6
32
42
33
43
diff view generated by jsdifflib
1
From: Tuguoyi <tu.guoyi@h3c.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
The local_err check outside of the if block was necessary
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
when it was introduced in commit d1258dd0c87 because it needed to be
5
executed even if qcow2_load_autoloading_dirty_bitmaps() returned false.
6
7
After some modifications that all required the error check to remain
8
where it is, commit 9c98f145dfb finally moved the
9
qcow2_load_dirty_bitmaps() call into the if block, so now the error
10
check should be there, too.
11
12
Signed-off-by: Guoyi Tu <tu.guoyi@h3c.com>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
5
---
16
block/qcow2.c | 10 +++++-----
6
include/block/block_int.h | 1 -
17
1 file changed, 5 insertions(+), 5 deletions(-)
7
block/io.c | 18 ------------------
8
2 files changed, 19 deletions(-)
18
9
19
diff --git a/block/qcow2.c b/block/qcow2.c
10
diff --git a/include/block/block_int.h b/include/block/block_int.h
20
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.c
12
--- a/include/block/block_int.h
22
+++ b/block/qcow2.c
13
+++ b/include/block/block_int.h
23
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
14
@@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk);
24
if (!(bdrv_get_flags(bs) & BDRV_O_INACTIVE)) {
15
bool blk_dev_is_medium_locked(BlockBackend *blk);
25
/* It's case 1, 2 or 3.2. Or 3.1 which is BUG in management layer. */
16
26
bool header_updated = qcow2_load_dirty_bitmaps(bs, &local_err);
17
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
27
+ if (local_err != NULL) {
18
-bool bdrv_requests_pending(BlockDriverState *bs);
28
+ error_propagate(errp, local_err);
19
29
+ ret = -EINVAL;
20
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
30
+ goto fail;
21
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
31
+ }
22
diff --git a/block/io.c b/block/io.c
32
23
index XXXXXXX..XXXXXXX 100644
33
update_header = update_header && !header_updated;
24
--- a/block/io.c
34
}
25
+++ b/block/io.c
35
- if (local_err != NULL) {
26
@@ -XXX,XX +XXX,XX @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
36
- error_propagate(errp, local_err);
27
assert(old >= 1);
37
- ret = -EINVAL;
28
}
38
- goto fail;
29
30
-/* Check if any requests are in-flight (including throttled requests) */
31
-bool bdrv_requests_pending(BlockDriverState *bs)
32
-{
33
- BdrvChild *child;
34
-
35
- if (atomic_read(&bs->in_flight)) {
36
- return true;
39
- }
37
- }
40
38
-
41
if (update_header) {
39
- QLIST_FOREACH(child, &bs->children, next) {
42
ret = qcow2_update_header(bs);
40
- if (bdrv_requests_pending(child->bs)) {
41
- return true;
42
- }
43
- }
44
-
45
- return false;
46
-}
47
-
48
typedef struct {
49
Coroutine *co;
50
BlockDriverState *bs;
43
--
51
--
44
2.20.1
52
2.13.6
45
53
46
54
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Fam Zheng <famz@redhat.com>
3
---
4
block/io.c | 6 ++++++
5
1 file changed, 6 insertions(+)
1
6
7
diff --git a/block/io.c b/block/io.c
8
index XXXXXXX..XXXXXXX 100644
9
--- a/block/io.c
10
+++ b/block/io.c
11
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
12
BdrvNextIterator it;
13
GSList *aio_ctxs = NULL, *ctx;
14
15
+ /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread
16
+ * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on
17
+ * nodes in several different AioContexts, so make sure we're in the main
18
+ * context. */
19
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
20
+
21
block_job_pause_all();
22
23
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
24
--
25
2.13.6
26
27
diff view generated by jsdifflib
1
The blockdev_create() function in this test case adds an error check
1
bdrv_drained_begin() doesn't increase bs->quiesce_counter recursively
2
that skips the test in case of failure because of memory shortage, but
2
and also doesn't notify other parent nodes of children, which both means
3
provides otherwise the same functionality as VM.blockdev_create() from
3
that the child nodes are not actually drained, and bdrv_drained_begin()
4
iotests.py. Make it a thin wrapper around the iotests.py function.
4
is providing useful functionality only on a single node.
5
6
To keep things consistent, we also shouldn't call the block driver
7
callbacks recursively.
8
9
A proper recursive drain version that provides an actually working
10
drained section for child nodes will be introduced later.
5
11
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
7
---
14
---
8
tests/qemu-iotests/211 | 12 +++---------
15
block/io.c | 16 +++++++++-------
9
1 file changed, 3 insertions(+), 9 deletions(-)
16
1 file changed, 9 insertions(+), 7 deletions(-)
10
17
11
diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211
18
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100755
19
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/211
20
--- a/block/io.c
14
+++ b/tests/qemu-iotests/211
21
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['vdi'])
22
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
16
iotests.verify_protocol(supported=['file'])
23
}
17
24
18
def blockdev_create(vm, options):
25
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
19
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
26
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
20
- filters=[iotests.filter_qmp_testfiles])
27
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive)
21
-
28
{
22
- if 'return' in result:
29
BdrvChild *child, *tmp;
23
- assert result['return'] == {}
30
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
24
- error = vm.run_job('job0')
31
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
25
- if error and 'Could not allocate bmap' in error:
32
bdrv_coroutine_enter(bs, data.co);
26
- iotests.notrun('Insufficient memory')
33
BDRV_POLL_WHILE(bs, !data.done);
27
- iotests.log("")
34
28
+ error = vm.blockdev_create(options)
35
- QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
29
+ if error and 'Could not allocate bmap' in error:
36
- bdrv_drain_invoke(child->bs, begin);
30
+ iotests.notrun('Insufficient memory')
37
+ if (recursive) {
31
38
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
32
with iotests.FilePath('t.vdi') as disk_path, \
39
+ bdrv_drain_invoke(child->bs, begin, true);
33
iotests.VM() as vm:
40
+ }
41
}
42
}
43
44
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
45
bdrv_parent_drained_begin(bs);
46
}
47
48
- bdrv_drain_invoke(bs, true);
49
+ bdrv_drain_invoke(bs, true, false);
50
bdrv_drain_recurse(bs);
51
}
52
53
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
54
}
55
56
/* Re-enable things in child-to-parent order */
57
- bdrv_drain_invoke(bs, false);
58
+ bdrv_drain_invoke(bs, false, false);
59
bdrv_parent_drained_end(bs);
60
aio_enable_external(bdrv_get_aio_context(bs));
61
}
62
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
63
aio_context_acquire(aio_context);
64
aio_disable_external(aio_context);
65
bdrv_parent_drained_begin(bs);
66
- bdrv_drain_invoke(bs, true);
67
+ bdrv_drain_invoke(bs, true, true);
68
aio_context_release(aio_context);
69
70
if (!g_slist_find(aio_ctxs, aio_context)) {
71
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
72
73
/* Re-enable things in child-to-parent order */
74
aio_context_acquire(aio_context);
75
- bdrv_drain_invoke(bs, false);
76
+ bdrv_drain_invoke(bs, false, true);
77
bdrv_parent_drained_end(bs);
78
aio_enable_external(aio_context);
79
aio_context_release(aio_context);
34
--
80
--
35
2.20.1
81
2.13.6
36
82
37
83
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.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
Some tests create huge (but sparse) files, and to be able to run those
6
Also, add a backing file to the test node to test whether the operations
4
tests in certain limited environments (like CI containers), we have to
7
work recursively.
5
check for the possibility to create such files first. Thus let's introduce
6
a common function to check for large files, and replace the already
7
existing checks in the iotests 005 and 220 with this function.
8
8
9
Signed-off-by: Thomas Huth <thuth@redhat.com>
10
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
10
---
13
tests/qemu-iotests/005 | 5 +----
11
tests/test-bdrv-drain.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-----
14
tests/qemu-iotests/220 | 6 ++----
12
1 file changed, 62 insertions(+), 7 deletions(-)
15
tests/qemu-iotests/common.rc | 10 ++++++++++
16
3 files changed, 13 insertions(+), 8 deletions(-)
17
13
18
diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
19
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/005
16
--- a/tests/test-bdrv-drain.c
21
+++ b/tests/qemu-iotests/005
17
+++ b/tests/test-bdrv-drain.c
22
@@ -XXX,XX +XXX,XX @@ fi
18
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = {
23
# Sanity check: For raw, we require a file system that permits the creation
19
24
# of a HUGE (but very sparse) file. Check we can create it before continuing.
20
.bdrv_co_drain_begin = bdrv_test_co_drain_begin,
25
if [ "$IMGFMT" = "raw" ]; then
21
.bdrv_co_drain_end = bdrv_test_co_drain_end,
26
- if ! truncate --size=5T "$TEST_IMG"; then
27
- _notrun "file system on $TEST_DIR does not support large enough files"
28
- fi
29
- rm "$TEST_IMG"
30
+ _require_large_file 5T
31
fi
32
33
echo
34
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
35
index XXXXXXX..XXXXXXX 100755
36
--- a/tests/qemu-iotests/220
37
+++ b/tests/qemu-iotests/220
38
@@ -XXX,XX +XXX,XX @@ echo "== Creating huge file =="
39
40
# Sanity check: We require a file system that permits the creation
41
# of a HUGE (but very sparse) file. tmpfs works, ext4 does not.
42
-if ! truncate --size=513T "$TEST_IMG"; then
43
- _notrun "file system on $TEST_DIR does not support large enough files"
44
-fi
45
-rm "$TEST_IMG"
46
+_require_large_file 513T
47
+
22
+
48
IMGOPTS='cluster_size=2M,refcount_bits=1' _make_test_img 513T
23
+ .bdrv_child_perm = bdrv_format_default_perms,
49
24
};
50
echo "== Populating refcounts =="
25
51
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
26
static void aio_ret_cb(void *opaque, int ret)
52
index XXXXXXX..XXXXXXX 100644
27
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
53
--- a/tests/qemu-iotests/common.rc
28
*aio_ret = ret;
54
+++ b/tests/qemu-iotests/common.rc
55
@@ -XXX,XX +XXX,XX @@ _require_drivers()
56
done
57
}
29
}
58
30
59
+# Check that we have a file system that allows huge (but very sparse) files
31
-static void test_drv_cb_drain_all(void)
60
+#
32
+enum drain_type {
61
+_require_large_file()
33
+ BDRV_DRAIN_ALL,
34
+ BDRV_DRAIN,
35
+};
36
+
37
+static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
62
+{
38
+{
63
+ if ! truncate --size="$1" "$TEST_IMG"; then
39
+ switch (drain_type) {
64
+ _notrun "file system on $TEST_DIR does not support large enough files"
40
+ case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
65
+ fi
41
+ case BDRV_DRAIN: bdrv_drained_begin(bs); break;
66
+ rm "$TEST_IMG"
42
+ default: g_assert_not_reached();
43
+ }
67
+}
44
+}
68
+
45
+
69
# make sure this script returns success
46
+static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
70
true
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
}
71
--
136
--
72
2.20.1
137
2.13.6
73
138
74
139
diff view generated by jsdifflib
1
Instead of having a separate blockdev_create() function, make use of the
1
This is currently only working correctly for bdrv_drain(), not for
2
VM.blockdev_create() offered by iotests.py.
2
bdrv_drain_all(). Leave a comment for the drain_all case, we'll address
3
it later.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
---
6
tests/qemu-iotests/237 | 139 +++++++++++++++++++----------------------
7
tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
7
1 file changed, 65 insertions(+), 74 deletions(-)
8
1 file changed, 45 insertions(+)
8
9
9
diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
10
index XXXXXXX..XXXXXXX 100755
11
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/qemu-iotests/237
12
--- a/tests/test-bdrv-drain.c
12
+++ b/tests/qemu-iotests/237
13
+++ b/tests/test-bdrv-drain.c
13
@@ -XXX,XX +XXX,XX @@ from iotests import imgfmt
14
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
14
15
test_drv_cb_common(BDRV_DRAIN, false);
15
iotests.verify_image_format(supported_fmts=['vmdk'])
16
}
16
17
17
-def blockdev_create(vm, options):
18
+static void test_quiesce_common(enum drain_type drain_type, bool recursive)
18
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
19
+{
19
- filters=[iotests.filter_qmp_testfiles])
20
+ BlockBackend *blk;
20
-
21
+ BlockDriverState *bs, *backing;
21
- if 'return' in result:
22
- assert result['return'] == {}
23
- vm.run_job('job0')
24
- iotests.log("")
25
-
26
with iotests.FilePath('t.vmdk') as disk_path, \
27
iotests.FilePath('t.vmdk.1') as extent1_path, \
28
iotests.FilePath('t.vmdk.2') as extent2_path, \
29
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
30
size = 5 * 1024 * 1024 * 1024
31
32
vm.launch()
33
- blockdev_create(vm, { 'driver': 'file',
34
- 'filename': disk_path,
35
- 'size': 0 })
36
+ vm.blockdev_create({ 'driver': 'file',
37
+ 'filename': disk_path,
38
+ 'size': 0 })
39
40
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
41
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
42
43
- blockdev_create(vm, { 'driver': imgfmt,
44
- 'file': 'imgfile',
45
- 'size': size })
46
+ vm.blockdev_create({ 'driver': imgfmt,
47
+ 'file': 'imgfile',
48
+ 'size': size })
49
vm.shutdown()
50
51
iotests.img_info_log(disk_path)
52
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
53
size = 64 * 1024 * 1024
54
55
vm.launch()
56
- blockdev_create(vm, { 'driver': 'file',
57
- 'filename': disk_path,
58
- 'size': 0 })
59
-
60
- blockdev_create(vm, { 'driver': imgfmt,
61
- 'file': {
62
- 'driver': 'file',
63
- 'filename': disk_path,
64
- },
65
- 'size': size,
66
- 'extents': [],
67
- 'subformat': 'monolithicSparse',
68
- 'adapter-type': 'ide',
69
- 'hwversion': '4',
70
- 'zeroed-grain': False })
71
+ vm.blockdev_create({ 'driver': 'file',
72
+ 'filename': disk_path,
73
+ 'size': 0 })
74
+
22
+
75
+ vm.blockdev_create({ 'driver': imgfmt,
23
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
76
+ 'file': {
24
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
77
+ 'driver': 'file',
25
+ &error_abort);
78
+ 'filename': disk_path,
26
+ blk_insert_bs(blk, bs, &error_abort);
79
+ },
80
+ 'size': size,
81
+ 'extents': [],
82
+ 'subformat': 'monolithicSparse',
83
+ 'adapter-type': 'ide',
84
+ 'hwversion': '4',
85
+ 'zeroed-grain': False })
86
vm.shutdown()
87
88
iotests.img_info_log(disk_path)
89
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
90
size = 32 * 1024 * 1024
91
92
vm.launch()
93
- blockdev_create(vm, { 'driver': 'file',
94
- 'filename': disk_path,
95
- 'size': 0 })
96
-
97
- blockdev_create(vm, { 'driver': imgfmt,
98
- 'file': {
99
- 'driver': 'file',
100
- 'filename': disk_path,
101
- },
102
- 'size': size,
103
- 'extents': [],
104
- 'subformat': 'monolithicSparse',
105
- 'adapter-type': 'buslogic',
106
- 'zeroed-grain': True })
107
+ vm.blockdev_create({ 'driver': 'file',
108
+ 'filename': disk_path,
109
+ 'size': 0 })
110
+
27
+
111
+ vm.blockdev_create({ 'driver': imgfmt,
28
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
112
+ 'file': {
29
+ bdrv_set_backing_hd(bs, backing, &error_abort);
113
+ 'driver': 'file',
30
+
114
+ 'filename': disk_path,
31
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
115
+ },
32
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
116
+ 'size': size,
33
+
117
+ 'extents': [],
34
+ do_drain_begin(drain_type, bs);
118
+ 'subformat': 'monolithicSparse',
35
+
119
+ 'adapter-type': 'buslogic',
36
+ g_assert_cmpint(bs->quiesce_counter, ==, 1);
120
+ 'zeroed-grain': True })
37
+ g_assert_cmpint(backing->quiesce_counter, ==, !!recursive);
121
vm.shutdown()
38
+
122
39
+ do_drain_end(drain_type, bs);
123
iotests.img_info_log(disk_path)
40
+
124
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
41
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
125
iotests.log("")
42
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
126
43
+
127
vm.launch()
44
+ bdrv_unref(backing);
128
- blockdev_create(vm, { 'driver': imgfmt,
45
+ bdrv_unref(bs);
129
- 'file': "this doesn't exist",
46
+ blk_unref(blk);
130
- 'size': size })
47
+}
131
+ vm.blockdev_create({ 'driver': imgfmt,
48
+
132
+ 'file': "this doesn't exist",
49
+static void test_quiesce_drain_all(void)
133
+ 'size': size })
50
+{
134
vm.shutdown()
51
+ // XXX drain_all doesn't quiesce
135
52
+ //test_quiesce_common(BDRV_DRAIN_ALL, true);
136
#
53
+}
137
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
54
+
138
55
+static void test_quiesce_drain(void)
139
vm.launch()
56
+{
140
for adapter_type in [ 'ide', 'buslogic', 'lsilogic', 'legacyESX' ]:
57
+ test_quiesce_common(BDRV_DRAIN, false);
141
- blockdev_create(vm, { 'driver': imgfmt,
58
+}
142
- 'file': 'node0',
59
+
143
- 'size': size,
60
int main(int argc, char **argv)
144
- 'adapter-type': adapter_type })
61
{
145
+ vm.blockdev_create({ 'driver': imgfmt,
62
bdrv_init();
146
+ 'file': 'node0',
63
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
147
+ 'size': size,
64
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
148
+ 'adapter-type': adapter_type })
65
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
149
vm.shutdown()
66
150
67
+ g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
151
# Invalid
68
+ g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
152
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
69
+
153
70
return g_test_run();
154
vm.launch()
71
}
155
for adapter_type in [ 'foo', 'IDE', 'legacyesx', 1 ]:
156
- blockdev_create(vm, { 'driver': imgfmt,
157
- 'file': 'node0',
158
- 'size': size,
159
- 'adapter-type': adapter_type })
160
+ vm.blockdev_create({ 'driver': imgfmt,
161
+ 'file': 'node0',
162
+ 'size': size,
163
+ 'adapter-type': adapter_type })
164
vm.shutdown()
165
166
#
167
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
168
iotests.log("")
169
170
vm.launch()
171
- blockdev_create(vm, { 'driver': imgfmt,
172
- 'file': 'node0',
173
- 'size': size,
174
- 'subformat': 'monolithicFlat' })
175
+ vm.blockdev_create({ 'driver': imgfmt,
176
+ 'file': 'node0',
177
+ 'size': size,
178
+ 'subformat': 'monolithicFlat' })
179
vm.shutdown()
180
181
# Correct extent
182
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
183
iotests.log("")
184
185
vm.launch()
186
- blockdev_create(vm, { 'driver': imgfmt,
187
- 'file': 'node0',
188
- 'size': size,
189
- 'subformat': 'monolithicFlat',
190
- 'extents': ['ext1'] })
191
+ vm.blockdev_create({ 'driver': imgfmt,
192
+ 'file': 'node0',
193
+ 'size': size,
194
+ 'subformat': 'monolithicFlat',
195
+ 'extents': ['ext1'] })
196
vm.shutdown()
197
198
# Extra extent
199
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
200
iotests.log("")
201
202
vm.launch()
203
- blockdev_create(vm, { 'driver': imgfmt,
204
- 'file': 'node0',
205
- 'size': 512,
206
- 'subformat': 'monolithicFlat',
207
- 'extents': ['ext1', 'ext2', 'ext3'] })
208
+ vm.blockdev_create({ 'driver': imgfmt,
209
+ 'file': 'node0',
210
+ 'size': 512,
211
+ 'subformat': 'monolithicFlat',
212
+ 'extents': ['ext1', 'ext2', 'ext3'] })
213
vm.shutdown()
214
215
# Split formats
216
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
217
extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ]
218
219
vm.launch()
220
- blockdev_create(vm, { 'driver': imgfmt,
221
- 'file': 'node0',
222
- 'size': size,
223
- 'subformat': subfmt,
224
- 'extents': extents })
225
+ vm.blockdev_create({ 'driver': imgfmt,
226
+ 'file': 'node0',
227
+ 'size': size,
228
+ 'subformat': subfmt,
229
+ 'extents': extents })
230
vm.shutdown()
231
232
iotests.img_info_log(disk_path)
233
--
72
--
234
2.20.1
73
2.13.6
235
74
236
75
diff view generated by jsdifflib
1
The error message for a negative speed uses QERR_INVALID_PARAMETER,
1
Block jobs already paused themselves when their main BlockBackend
2
which implies that the 'speed' option doesn't even exist:
2
entered a drained section. This is not good enough: We also want to
3
pause a block job and may not submit new requests if, for example, the
4
mirror target node should be drained.
3
5
4
{"error": {"class": "GenericError", "desc": "Invalid parameter 'speed'"}}
6
This implements .drained_begin/end callbacks in child_job in order to
5
7
consider all block nodes related to the job, and removes the
6
Make it use QERR_INVALID_PARAMETER_VALUE instead:
8
BlockBackend callbacks which are unnecessary now because the root of the
7
9
job main BlockBackend is always referenced with a child_job, too.
8
{"error": {"class": "GenericError", "desc": "Parameter 'speed' expects a non-negative value"}}
9
10
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
---
12
---
14
blockjob.c | 3 ++-
13
blockjob.c | 22 +++++++++-------------
15
tests/qemu-iotests/030 | 4 ++--
14
1 file changed, 9 insertions(+), 13 deletions(-)
16
2 files changed, 4 insertions(+), 3 deletions(-)
17
15
18
diff --git a/blockjob.c b/blockjob.c
16
diff --git a/blockjob.c b/blockjob.c
19
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
20
--- a/blockjob.c
18
--- a/blockjob.c
21
+++ b/blockjob.c
19
+++ b/blockjob.c
22
@@ -XXX,XX +XXX,XX @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
20
@@ -XXX,XX +XXX,XX @@ static char *child_job_get_parent_desc(BdrvChild *c)
23
return;
21
job->id);
24
}
22
}
25
if (speed < 0) {
23
26
- error_setg(errp, QERR_INVALID_PARAMETER, "speed");
24
-static const BdrvChildRole child_job = {
27
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "speed",
25
- .get_parent_desc = child_job_get_parent_desc,
28
+ "a non-negative value");
26
- .stay_at_node = true,
29
return;
27
-};
30
}
28
-
31
29
-static void block_job_drained_begin(void *opaque)
32
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
30
+static void child_job_drained_begin(BdrvChild *c)
33
index XXXXXXX..XXXXXXX 100755
31
{
34
--- a/tests/qemu-iotests/030
32
- BlockJob *job = opaque;
35
+++ b/tests/qemu-iotests/030
33
+ BlockJob *job = c->opaque;
36
@@ -XXX,XX +XXX,XX @@ class TestSetSpeed(iotests.QMPTestCase):
34
block_job_pause(job);
37
self.assert_no_active_block_jobs()
35
}
38
36
39
result = self.vm.qmp('block-stream', device='drive0', speed=-1)
37
-static void block_job_drained_end(void *opaque)
40
- self.assert_qmp(result, 'error/desc', "Invalid parameter 'speed'")
38
+static void child_job_drained_end(BdrvChild *c)
41
+ self.assert_qmp(result, 'error/desc', "Parameter 'speed' expects a non-negative value")
39
{
42
40
- BlockJob *job = opaque;
43
self.assert_no_active_block_jobs()
41
+ BlockJob *job = c->opaque;
44
42
block_job_resume(job);
45
@@ -XXX,XX +XXX,XX @@ class TestSetSpeed(iotests.QMPTestCase):
43
}
46
self.assert_qmp(result, 'return', {})
44
47
45
-static const BlockDevOps block_job_dev_ops = {
48
result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
46
- .drained_begin = block_job_drained_begin,
49
- self.assert_qmp(result, 'error/desc', "Invalid parameter 'speed'")
47
- .drained_end = block_job_drained_end,
50
+ self.assert_qmp(result, 'error/desc', "Parameter 'speed' expects a non-negative value")
48
+static const BdrvChildRole child_job = {
51
49
+ .get_parent_desc = child_job_get_parent_desc,
52
self.cancel_and_wait(resume=True)
50
+ .drained_begin = child_job_drained_begin,
53
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);
54
--
64
--
55
2.20.1
65
2.13.6
56
66
57
67
diff view generated by jsdifflib
1
Instead of having a separate blockdev_create() function, make use of the
1
Block jobs must be paused if any of the involved nodes are drained.
2
VM.blockdev_create() offered by iotests.py.
3
2
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
4
---
6
tests/qemu-iotests/213 | 113 +++++++++++++++++++----------------------
5
tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++
7
1 file changed, 52 insertions(+), 61 deletions(-)
6
1 file changed, 121 insertions(+)
8
7
9
diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
10
index XXXXXXX..XXXXXXX 100755
9
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/qemu-iotests/213
10
--- a/tests/test-bdrv-drain.c
12
+++ b/tests/qemu-iotests/213
11
+++ b/tests/test-bdrv-drain.c
13
@@ -XXX,XX +XXX,XX @@ from iotests import imgfmt
12
@@ -XXX,XX +XXX,XX @@
14
iotests.verify_image_format(supported_fmts=['vhdx'])
13
15
iotests.verify_protocol(supported=['file'])
14
#include "qemu/osdep.h"
16
15
#include "block/block.h"
17
-def blockdev_create(vm, options):
16
+#include "block/blockjob_int.h"
18
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
17
#include "sysemu/block-backend.h"
19
- filters=[iotests.filter_qmp_testfiles])
18
#include "qapi/error.h"
20
-
19
21
- if 'return' in result:
20
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
22
- assert result['return'] == {}
21
test_quiesce_common(BDRV_DRAIN, false);
23
- vm.run_job('job0')
22
}
24
- iotests.log("")
23
25
-
24
+
26
with iotests.FilePath('t.vhdx') as disk_path, \
25
+typedef struct TestBlockJob {
27
iotests.VM() as vm:
26
+ BlockJob common;
28
27
+ bool should_complete;
29
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
28
+} TestBlockJob;
30
size = 128 * 1024 * 1024
29
+
31
30
+static void test_job_completed(BlockJob *job, void *opaque)
32
vm.launch()
31
+{
33
- blockdev_create(vm, { 'driver': 'file',
32
+ block_job_completed(job, 0);
34
- 'filename': disk_path,
33
+}
35
- 'size': 0 })
34
+
36
+ vm.blockdev_create({ 'driver': 'file',
35
+static void coroutine_fn test_job_start(void *opaque)
37
+ 'filename': disk_path,
36
+{
38
+ 'size': 0 })
37
+ TestBlockJob *s = opaque;
39
38
+
40
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
39
+ while (!s->should_complete) {
41
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
40
+ block_job_sleep_ns(&s->common, 100000);
42
41
+ }
43
- blockdev_create(vm, { 'driver': imgfmt,
42
+
44
- 'file': 'imgfile',
43
+ block_job_defer_to_main_loop(&s->common, test_job_completed, NULL);
45
- 'size': size })
44
+}
46
+ vm.blockdev_create({ 'driver': imgfmt,
45
+
47
+ 'file': 'imgfile',
46
+static void test_job_complete(BlockJob *job, Error **errp)
48
+ 'size': size })
47
+{
49
vm.shutdown()
48
+ TestBlockJob *s = container_of(job, TestBlockJob, common);
50
49
+ s->should_complete = true;
51
iotests.img_info_log(disk_path)
50
+}
52
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
51
+
53
size = 64 * 1024 * 1024
52
+BlockJobDriver test_job_driver = {
54
53
+ .instance_size = sizeof(TestBlockJob),
55
vm.launch()
54
+ .start = test_job_start,
56
- blockdev_create(vm, { 'driver': 'file',
55
+ .complete = test_job_complete,
57
- 'filename': disk_path,
56
+};
58
- 'size': 0 })
57
+
59
- blockdev_create(vm, { 'driver': imgfmt,
58
+static void test_blockjob_common(enum drain_type drain_type)
60
- 'file': {
59
+{
61
- 'driver': 'file',
60
+ BlockBackend *blk_src, *blk_target;
62
- 'filename': disk_path,
61
+ BlockDriverState *src, *target;
63
- },
62
+ BlockJob *job;
64
- 'size': size,
63
+ int ret;
65
- 'log-size': 1048576,
64
+
66
- 'block-size': 8388608,
65
+ src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR,
67
- 'subformat': 'dynamic',
66
+ &error_abort);
68
- 'block-state-zero': True })
67
+ blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
69
+ vm.blockdev_create({ 'driver': 'file',
68
+ blk_insert_bs(blk_src, src, &error_abort);
70
+ 'filename': disk_path,
69
+
71
+ 'size': 0 })
70
+ target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
72
+ vm.blockdev_create({ 'driver': imgfmt,
71
+ &error_abort);
73
+ 'file': {
72
+ blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
74
+ 'driver': 'file',
73
+ blk_insert_bs(blk_target, target, &error_abort);
75
+ 'filename': disk_path,
74
+
76
+ },
75
+ job = block_job_create("job0", &test_job_driver, src, 0, BLK_PERM_ALL, 0,
77
+ 'size': size,
76
+ 0, NULL, NULL, &error_abort);
78
+ 'log-size': 1048576,
77
+ block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
79
+ 'block-size': 8388608,
78
+ block_job_start(job);
80
+ 'subformat': 'dynamic',
79
+
81
+ 'block-state-zero': True })
80
+ g_assert_cmpint(job->pause_count, ==, 0);
82
vm.shutdown()
81
+ g_assert_false(job->paused);
83
82
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
84
iotests.img_info_log(disk_path)
83
+
85
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
84
+ do_drain_begin(drain_type, src);
86
size = 32 * 1024 * 1024
85
+
87
86
+ if (drain_type == BDRV_DRAIN_ALL) {
88
vm.launch()
87
+ /* bdrv_drain_all() drains both src and target, and involves an
89
- blockdev_create(vm, { 'driver': 'file',
88
+ * additional block_job_pause_all() */
90
- 'filename': disk_path,
89
+ g_assert_cmpint(job->pause_count, ==, 3);
91
- 'size': 0 })
90
+ } else {
92
- blockdev_create(vm, { 'driver': imgfmt,
91
+ g_assert_cmpint(job->pause_count, ==, 1);
93
- 'file': {
92
+ }
94
- 'driver': 'file',
93
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
95
- 'filename': disk_path,
94
+ /* g_assert_true(job->paused); */
96
- },
95
+ g_assert_false(job->busy); /* The job is paused */
97
- 'size': size,
96
+
98
- 'log-size': 8388608,
97
+ do_drain_end(drain_type, src);
99
- 'block-size': 268435456,
98
+
100
- 'subformat': 'fixed',
99
+ g_assert_cmpint(job->pause_count, ==, 0);
101
- 'block-state-zero': False })
100
+ g_assert_false(job->paused);
102
+ vm.blockdev_create({ 'driver': 'file',
101
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
103
+ 'filename': disk_path,
102
+
104
+ 'size': 0 })
103
+ do_drain_begin(drain_type, target);
105
+ vm.blockdev_create({ 'driver': imgfmt,
104
+
106
+ 'file': {
105
+ if (drain_type == BDRV_DRAIN_ALL) {
107
+ 'driver': 'file',
106
+ /* bdrv_drain_all() drains both src and target, and involves an
108
+ 'filename': disk_path,
107
+ * additional block_job_pause_all() */
109
+ },
108
+ g_assert_cmpint(job->pause_count, ==, 3);
110
+ 'size': size,
109
+ } else {
111
+ 'log-size': 8388608,
110
+ g_assert_cmpint(job->pause_count, ==, 1);
112
+ 'block-size': 268435456,
111
+ }
113
+ 'subformat': 'fixed',
112
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
114
+ 'block-state-zero': False })
113
+ /* g_assert_true(job->paused); */
115
vm.shutdown()
114
+ g_assert_false(job->busy); /* The job is paused */
116
115
+
117
iotests.img_info_log(disk_path)
116
+ do_drain_end(drain_type, target);
118
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
117
+
119
iotests.log("")
118
+ g_assert_cmpint(job->pause_count, ==, 0);
120
119
+ g_assert_false(job->paused);
121
vm.launch()
120
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
122
- blockdev_create(vm, { 'driver': imgfmt,
121
+
123
- 'file': "this doesn't exist",
122
+ ret = block_job_complete_sync(job, &error_abort);
124
- 'size': size })
123
+ g_assert_cmpint(ret, ==, 0);
125
+ vm.blockdev_create({ 'driver': imgfmt,
124
+
126
+ 'file': "this doesn't exist",
125
+ blk_unref(blk_src);
127
+ 'size': size })
126
+ blk_unref(blk_target);
128
vm.shutdown()
127
+ bdrv_unref(src);
129
128
+ bdrv_unref(target);
130
#
129
+}
131
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
130
+
132
131
+static void test_blockjob_drain_all(void)
133
vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
132
+{
134
vm.launch()
133
+ test_blockjob_common(BDRV_DRAIN_ALL);
135
- blockdev_create(vm, { 'driver': imgfmt,
134
+}
136
- 'file': 'node0',
135
+
137
- 'size': 0 })
136
+static void test_blockjob_drain(void)
138
+ vm.blockdev_create({ 'driver': imgfmt,
137
+{
139
+ 'file': 'node0',
138
+ test_blockjob_common(BDRV_DRAIN);
140
+ 'size': 0 })
139
+}
141
vm.shutdown()
140
+
142
141
int main(int argc, char **argv)
143
iotests.img_info_log(disk_path)
142
{
144
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
143
bdrv_init();
145
iotests.log("")
144
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
146
145
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
147
vm.launch()
146
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
148
- blockdev_create(vm, { 'driver': imgfmt,
147
149
- 'file': 'node0',
148
+ g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
150
- 'size': 70368744177664 })
149
+ g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
151
+ vm.blockdev_create({ 'driver': imgfmt,
150
+
152
+ 'file': 'node0',
151
return g_test_run();
153
+ 'size': 70368744177664 })
152
}
154
vm.shutdown()
155
156
iotests.img_info_log(disk_path)
157
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
158
vm.launch()
159
for size in [ 18446744073709551104, 9223372036854775808,
160
9223372036854775296, 70368744177665 ]:
161
- blockdev_create(vm, { 'driver': imgfmt,
162
- 'file': 'node0',
163
- 'size': size })
164
+ vm.blockdev_create({ 'driver': imgfmt,
165
+ 'file': 'node0',
166
+ 'size': size })
167
vm.shutdown()
168
169
#
170
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
171
172
vm.launch()
173
for bsize in [ 1234567, 128, 3145728, 536870912, 0 ]:
174
- blockdev_create(vm, { 'driver': imgfmt,
175
- 'file': 'node0',
176
- 'size': 67108864,
177
- 'block-size': bsize })
178
+ vm.blockdev_create({ 'driver': imgfmt,
179
+ 'file': 'node0',
180
+ 'size': 67108864,
181
+ 'block-size': bsize })
182
vm.shutdown()
183
184
#
185
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
186
187
vm.launch()
188
for lsize in [ 1234567, 128, 4294967296, 0 ]:
189
- blockdev_create(vm, { 'driver': imgfmt,
190
- 'file': 'node0',
191
- 'size': 67108864,
192
- 'log-size': lsize })
193
+ vm.blockdev_create({ 'driver': imgfmt,
194
+ 'file': 'node0',
195
+ 'size': 67108864,
196
+ 'log-size': lsize })
197
vm.shutdown()
198
--
153
--
199
2.20.1
154
2.13.6
200
155
201
156
diff view generated by jsdifflib
1
Instead of having a separate blockdev_create() function, make use of the
1
Block jobs are already paused using the BdrvChildRole drain callbacks,
2
VM.blockdev_create() offered by iotests.py.
2
so we don't need an additional block_job_pause_all() call.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
5
---
6
tests/qemu-iotests/212 | 101 +++++++++++++++++++----------------------
6
block/io.c | 4 ----
7
1 file changed, 46 insertions(+), 55 deletions(-)
7
tests/test-bdrv-drain.c | 10 ++++------
8
2 files changed, 4 insertions(+), 10 deletions(-)
8
9
9
diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212
10
diff --git a/block/io.c b/block/io.c
10
index XXXXXXX..XXXXXXX 100755
11
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/qemu-iotests/212
12
--- a/block/io.c
12
+++ b/tests/qemu-iotests/212
13
+++ b/block/io.c
13
@@ -XXX,XX +XXX,XX @@ from iotests import imgfmt
14
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
14
iotests.verify_image_format(supported_fmts=['parallels'])
15
* context. */
15
iotests.verify_protocol(supported=['file'])
16
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
16
17
17
-def blockdev_create(vm, options):
18
- block_job_pause_all();
18
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
19
- filters=[iotests.filter_qmp_testfiles])
20
-
19
-
21
- if 'return' in result:
20
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
22
- assert result['return'] == {}
21
AioContext *aio_context = bdrv_get_aio_context(bs);
23
- vm.run_job('job0')
22
24
- iotests.log("")
23
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
24
aio_enable_external(aio_context);
25
aio_context_release(aio_context);
26
}
25
-
27
-
26
with iotests.FilePath('t.parallels') as disk_path, \
28
- block_job_resume_all();
27
iotests.VM() as vm:
29
}
28
30
29
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
31
void bdrv_drain_all(void)
30
size = 128 * 1024 * 1024
32
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
31
33
index XXXXXXX..XXXXXXX 100644
32
vm.launch()
34
--- a/tests/test-bdrv-drain.c
33
- blockdev_create(vm, { 'driver': 'file',
35
+++ b/tests/test-bdrv-drain.c
34
- 'filename': disk_path,
36
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
35
- 'size': 0 })
37
do_drain_begin(drain_type, src);
36
+ vm.blockdev_create({ 'driver': 'file',
38
37
+ 'filename': disk_path,
39
if (drain_type == BDRV_DRAIN_ALL) {
38
+ 'size': 0 })
40
- /* bdrv_drain_all() drains both src and target, and involves an
39
41
- * additional block_job_pause_all() */
40
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
42
- g_assert_cmpint(job->pause_count, ==, 3);
41
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
43
+ /* bdrv_drain_all() drains both src and target */
42
44
+ g_assert_cmpint(job->pause_count, ==, 2);
43
- blockdev_create(vm, { 'driver': imgfmt,
45
} else {
44
- 'file': 'imgfile',
46
g_assert_cmpint(job->pause_count, ==, 1);
45
- 'size': size })
47
}
46
+ vm.blockdev_create({ 'driver': imgfmt,
48
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
47
+ 'file': 'imgfile',
49
do_drain_begin(drain_type, target);
48
+ 'size': size })
50
49
vm.shutdown()
51
if (drain_type == BDRV_DRAIN_ALL) {
50
52
- /* bdrv_drain_all() drains both src and target, and involves an
51
iotests.img_info_log(disk_path)
53
- * additional block_job_pause_all() */
52
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
54
- g_assert_cmpint(job->pause_count, ==, 3);
53
size = 64 * 1024 * 1024
55
+ /* bdrv_drain_all() drains both src and target */
54
56
+ g_assert_cmpint(job->pause_count, ==, 2);
55
vm.launch()
57
} else {
56
- blockdev_create(vm, { 'driver': 'file',
58
g_assert_cmpint(job->pause_count, ==, 1);
57
- 'filename': disk_path,
59
}
58
- 'size': 0 })
59
- blockdev_create(vm, { 'driver': imgfmt,
60
- 'file': {
61
- 'driver': 'file',
62
- 'filename': disk_path,
63
- },
64
- 'size': size,
65
- 'cluster-size': 1048576 })
66
+ vm.blockdev_create({ 'driver': 'file',
67
+ 'filename': disk_path,
68
+ 'size': 0 })
69
+ vm.blockdev_create({ 'driver': imgfmt,
70
+ 'file': {
71
+ 'driver': 'file',
72
+ 'filename': disk_path,
73
+ },
74
+ 'size': size,
75
+ 'cluster-size': 1048576 })
76
vm.shutdown()
77
78
iotests.img_info_log(disk_path)
79
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
80
size = 32 * 1024 * 1024
81
82
vm.launch()
83
- blockdev_create(vm, { 'driver': 'file',
84
- 'filename': disk_path,
85
- 'size': 0 })
86
- blockdev_create(vm, { 'driver': imgfmt,
87
- 'file': {
88
- 'driver': 'file',
89
- 'filename': disk_path,
90
- },
91
- 'size': size,
92
- 'cluster-size': 65536 })
93
+ vm.blockdev_create({ 'driver': 'file',
94
+ 'filename': disk_path,
95
+ 'size': 0 })
96
+ vm.blockdev_create({ 'driver': imgfmt,
97
+ 'file': {
98
+ 'driver': 'file',
99
+ 'filename': disk_path,
100
+ },
101
+ 'size': size,
102
+ 'cluster-size': 65536 })
103
vm.shutdown()
104
105
iotests.img_info_log(disk_path)
106
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
107
iotests.log("")
108
109
vm.launch()
110
- blockdev_create(vm, { 'driver': imgfmt,
111
- 'file': "this doesn't exist",
112
- 'size': size })
113
+ vm.blockdev_create({ 'driver': imgfmt,
114
+ 'file': "this doesn't exist",
115
+ 'size': size })
116
vm.shutdown()
117
118
#
119
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
120
121
vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
122
vm.launch()
123
- blockdev_create(vm, { 'driver': imgfmt,
124
- 'file': 'node0',
125
- 'size': 0 })
126
+ vm.blockdev_create({ 'driver': imgfmt,
127
+ 'file': 'node0',
128
+ 'size': 0 })
129
vm.shutdown()
130
131
iotests.img_info_log(disk_path)
132
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
133
iotests.log("")
134
135
vm.launch()
136
- blockdev_create(vm, { 'driver': imgfmt,
137
- 'file': 'node0',
138
- 'size': 4503599627369984})
139
+ vm.blockdev_create({ 'driver': imgfmt,
140
+ 'file': 'node0',
141
+ 'size': 4503599627369984})
142
vm.shutdown()
143
144
iotests.img_info_log(disk_path)
145
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
146
vm.launch()
147
for size in [ 1234, 18446744073709551104, 9223372036854775808,
148
9223372036854775296, 4503599627370497 ]:
149
- blockdev_create(vm, { 'driver': imgfmt,
150
- 'file': 'node0',
151
- 'size': size })
152
+ vm.blockdev_create({ 'driver': imgfmt,
153
+ 'file': 'node0',
154
+ 'size': size })
155
vm.shutdown()
156
157
#
158
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
159
vm.launch()
160
for csize in [ 1234, 128, 4294967296, 9223372036854775808,
161
18446744073709551104, 0 ]:
162
- blockdev_create(vm, { 'driver': imgfmt,
163
- 'file': 'node0',
164
- 'size': 67108864,
165
- 'cluster-size': csize })
166
- blockdev_create(vm, { 'driver': imgfmt,
167
- 'file': 'node0',
168
- 'size': 281474976710656,
169
- 'cluster-size': 512 })
170
+ vm.blockdev_create({ 'driver': imgfmt,
171
+ 'file': 'node0',
172
+ 'size': 67108864,
173
+ 'cluster-size': csize })
174
+ vm.blockdev_create({ 'driver': imgfmt,
175
+ 'file': 'node0',
176
+ 'size': 281474976710656,
177
+ 'cluster-size': 512 })
178
vm.shutdown()
179
--
60
--
180
2.20.1
61
2.13.6
181
62
182
63
diff view generated by jsdifflib
1
Instead of having a separate blockdev_create() function, make use of the
1
bdrv_do_drained_begin() restricts the call of parent callbacks and
2
VM.blockdev_create() offered by iotests.py.
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.
3
6
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
8
---
6
tests/qemu-iotests/210 | 81 +++++++++++++++++++-----------------------
9
block/io.c | 12 +++++++-----
7
1 file changed, 36 insertions(+), 45 deletions(-)
10
1 file changed, 7 insertions(+), 5 deletions(-)
8
11
9
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
12
diff --git a/block/io.c b/block/io.c
10
index XXXXXXX..XXXXXXX 100755
13
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/qemu-iotests/210
14
--- a/block/io.c
12
+++ b/tests/qemu-iotests/210
15
+++ b/block/io.c
13
@@ -XXX,XX +XXX,XX @@ from iotests import imgfmt
16
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
14
iotests.verify_image_format(supported_fmts=['luks'])
17
15
iotests.verify_protocol(supported=['file'])
18
void bdrv_drained_end(BlockDriverState *bs)
16
19
{
17
-def blockdev_create(vm, options):
20
+ int old_quiesce_counter;
18
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
21
+
19
- filters=[iotests.filter_qmp_testfiles])
22
if (qemu_in_coroutine()) {
20
-
23
bdrv_co_yield_to_drain(bs, false);
21
- if 'return' in result:
24
return;
22
- assert result['return'] == {}
25
}
23
- vm.run_job('job0')
26
assert(bs->quiesce_counter > 0);
24
- iotests.log("")
27
- if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
25
-
28
- return;
26
with iotests.FilePath('t.luks') as disk_path, \
29
- }
27
iotests.VM() as vm:
30
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
28
31
29
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
32
/* Re-enable things in child-to-parent order */
30
size = 128 * 1024 * 1024
33
bdrv_drain_invoke(bs, false, false);
31
34
- bdrv_parent_drained_end(bs);
32
vm.launch()
35
- aio_enable_external(bdrv_get_aio_context(bs));
33
- blockdev_create(vm, { 'driver': 'file',
36
+ if (old_quiesce_counter == 1) {
34
- 'filename': disk_path,
37
+ bdrv_parent_drained_end(bs);
35
- 'size': 0 })
38
+ aio_enable_external(bdrv_get_aio_context(bs));
36
+ vm.blockdev_create({ 'driver': 'file',
39
+ }
37
+ 'filename': disk_path,
40
}
38
+ 'size': 0 })
41
39
42
/*
40
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
41
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
42
43
- blockdev_create(vm, { 'driver': imgfmt,
44
- 'file': 'imgfile',
45
- 'key-secret': 'keysec0',
46
- 'size': size,
47
- 'iter-time': 10 })
48
+ vm.blockdev_create({ 'driver': imgfmt,
49
+ 'file': 'imgfile',
50
+ 'key-secret': 'keysec0',
51
+ 'size': size,
52
+ 'iter-time': 10 })
53
vm.shutdown()
54
55
# TODO Proper support for images to be used with imgopts and/or protocols
56
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
57
size = 64 * 1024 * 1024
58
59
vm.launch()
60
- blockdev_create(vm, { 'driver': 'file',
61
- 'filename': disk_path,
62
- 'size': 0 })
63
- blockdev_create(vm, { 'driver': imgfmt,
64
- 'file': {
65
- 'driver': 'file',
66
- 'filename': disk_path,
67
- },
68
- 'size': size,
69
- 'key-secret': 'keysec0',
70
- 'cipher-alg': 'twofish-128',
71
- 'cipher-mode': 'ctr',
72
- 'ivgen-alg': 'plain64',
73
- 'ivgen-hash-alg': 'md5',
74
- 'hash-alg': 'sha1',
75
- 'iter-time': 10 })
76
+ vm.blockdev_create({ 'driver': 'file',
77
+ 'filename': disk_path,
78
+ 'size': 0 })
79
+ vm.blockdev_create({ 'driver': imgfmt,
80
+ 'file': {
81
+ 'driver': 'file',
82
+ 'filename': disk_path,
83
+ },
84
+ 'size': size,
85
+ 'key-secret': 'keysec0',
86
+ 'cipher-alg': 'twofish-128',
87
+ 'cipher-mode': 'ctr',
88
+ 'ivgen-alg': 'plain64',
89
+ 'ivgen-hash-alg': 'md5',
90
+ 'hash-alg': 'sha1',
91
+ 'iter-time': 10 })
92
vm.shutdown()
93
94
# TODO Proper support for images to be used with imgopts and/or protocols
95
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
96
size = 64 * 1024 * 1024
97
98
vm.launch()
99
- blockdev_create(vm, { 'driver': imgfmt,
100
- 'file': "this doesn't exist",
101
- 'size': size })
102
+ vm.blockdev_create({ 'driver': imgfmt,
103
+ 'file': "this doesn't exist",
104
+ 'size': size })
105
vm.shutdown()
106
107
#
108
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
109
110
vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
111
vm.launch()
112
- blockdev_create(vm, { 'driver': imgfmt,
113
- 'file': 'node0',
114
- 'key-secret': 'keysec0',
115
- 'size': 0,
116
- 'iter-time': 10 })
117
+ vm.blockdev_create({ 'driver': imgfmt,
118
+ 'file': 'node0',
119
+ 'key-secret': 'keysec0',
120
+ 'size': 0,
121
+ 'iter-time': 10 })
122
vm.shutdown()
123
124
# TODO Proper support for images to be used with imgopts and/or protocols
125
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
126
127
vm.launch()
128
for size in [ 18446744073709551104, 9223372036854775808, 9223372036854775296 ]:
129
- blockdev_create(vm, { 'driver': imgfmt,
130
- 'file': 'node0',
131
- 'key-secret': 'keysec0',
132
- 'size': size })
133
+ vm.blockdev_create({ 'driver': imgfmt,
134
+ 'file': 'node0',
135
+ 'key-secret': 'keysec0',
136
+ 'size': size })
137
vm.shutdown()
138
139
#
140
--
43
--
141
2.20.1
44
2.13.6
142
45
143
46
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
2
3
Doing this allows running this test with e.g. -o compat=0.10 or
4
-o compat=refcount_bits=1.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
2
---
9
tests/qemu-iotests/273 | 3 ++-
3
tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/273.out | 27 ---------------------------
4
1 file changed, 57 insertions(+)
11
2 files changed, 2 insertions(+), 28 deletions(-)
12
5
13
diff --git a/tests/qemu-iotests/273 b/tests/qemu-iotests/273
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
index XXXXXXX..XXXXXXX 100755
7
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/273
8
--- a/tests/test-bdrv-drain.c
16
+++ b/tests/qemu-iotests/273
9
+++ b/tests/test-bdrv-drain.c
17
@@ -XXX,XX +XXX,XX @@ do_run_qemu()
10
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
18
run_qemu()
11
enum drain_type {
19
{
12
BDRV_DRAIN_ALL,
20
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp |
13
BDRV_DRAIN,
21
- _filter_generated_node_ids | _filter_imgfmt | _filter_actual_image_size
14
+ DRAIN_TYPE_MAX,
22
+ _filter_generated_node_ids | _filter_imgfmt |
15
};
23
+ _filter_actual_image_size | _filter_img_info
16
17
static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
18
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
19
test_quiesce_common(BDRV_DRAIN, false);
24
}
20
}
25
21
26
TEST_IMG="$TEST_IMG.base" _make_test_img 64M
22
+static void test_nested(void)
27
diff --git a/tests/qemu-iotests/273.out b/tests/qemu-iotests/273.out
23
+{
28
index XXXXXXX..XXXXXXX 100644
24
+ BlockBackend *blk;
29
--- a/tests/qemu-iotests/273.out
25
+ BlockDriverState *bs, *backing;
30
+++ b/tests/qemu-iotests/273.out
26
+ BDRVTestState *s, *backing_s;
31
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
27
+ enum drain_type outer, inner;
32
"cluster-size": 65536,
28
+
33
"format": "IMGFMT",
29
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
34
"actual-size": SIZE,
30
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
35
- "format-specific": {
31
+ &error_abort);
36
- "type": "IMGFMT",
32
+ s = bs->opaque;
37
- "data": {
33
+ blk_insert_bs(blk, bs, &error_abort);
38
- "compat": "1.1",
34
+
39
- "lazy-refcounts": false,
35
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
40
- "refcount-bits": 16,
36
+ backing_s = backing->opaque;
41
- "corrupt": false
37
+ bdrv_set_backing_hd(bs, backing, &error_abort);
42
- }
38
+
43
- },
39
+ for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
44
"full-backing-filename": "TEST_DIR/t.IMGFMT.base",
40
+ for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
45
"backing-filename": "TEST_DIR/t.IMGFMT.base",
41
+ /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
46
"dirty-flag": false
42
+ int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
47
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
43
+ (inner != BDRV_DRAIN_ALL);
48
"cluster-size": 65536,
44
+ int backing_quiesce = 0;
49
"format": "IMGFMT",
45
+ int backing_cb_cnt = (outer != BDRV_DRAIN) +
50
"actual-size": SIZE,
46
+ (inner != BDRV_DRAIN);
51
- "format-specific": {
47
+
52
- "type": "IMGFMT",
48
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
53
- "data": {
49
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
54
- "compat": "1.1",
50
+ g_assert_cmpint(s->drain_count, ==, 0);
55
- "lazy-refcounts": false,
51
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
56
- "refcount-bits": 16,
52
+
57
- "corrupt": false
53
+ do_drain_begin(outer, bs);
58
- }
54
+ do_drain_begin(inner, bs);
59
- },
55
+
60
"full-backing-filename": "TEST_DIR/t.IMGFMT.mid",
56
+ g_assert_cmpint(bs->quiesce_counter, ==, bs_quiesce);
61
"backing-filename": "TEST_DIR/t.IMGFMT.mid",
57
+ g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce);
62
"dirty-flag": false
58
+ g_assert_cmpint(s->drain_count, ==, 2);
63
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
59
+ g_assert_cmpint(backing_s->drain_count, ==, backing_cb_cnt);
64
"cluster-size": 65536,
60
+
65
"format": "IMGFMT",
61
+ do_drain_end(inner, bs);
66
"actual-size": SIZE,
62
+ do_drain_end(outer, bs);
67
- "format-specific": {
63
+
68
- "type": "IMGFMT",
64
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
69
- "data": {
65
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
70
- "compat": "1.1",
66
+ g_assert_cmpint(s->drain_count, ==, 0);
71
- "lazy-refcounts": false,
67
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
72
- "refcount-bits": 16,
68
+ }
73
- "corrupt": false
69
+ }
74
- }
70
+
75
- },
71
+ bdrv_unref(backing);
76
"full-backing-filename": "TEST_DIR/t.IMGFMT.base",
72
+ bdrv_unref(bs);
77
"backing-filename": "TEST_DIR/t.IMGFMT.base",
73
+ blk_unref(blk);
78
"dirty-flag": false
74
+}
75
+
76
77
typedef struct TestBlockJob {
78
BlockJob common;
79
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
80
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
81
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
82
83
+ g_test_add_func("/bdrv-drain/nested", test_nested);
84
+
85
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
86
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
87
79
--
88
--
80
2.20.1
89
2.13.6
81
90
82
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
In the common case, qcow2_co_pwrite_zeroes() already only modifies
1
bdrv_drained_begin() waits for the completion of requests in the whole
2
metadata case, so we're fine with or without BDRV_REQ_NO_FALLBACK set.
2
subtree, but it only actually keeps its immediate bs parameter quiesced
3
until bdrv_drained_end().
3
4
4
The only exception is when using an external data file, where the
5
Add a version that keeps the whole subtree drained. As of this commit,
5
request is passed down to the block driver of the external data file. We
6
graph changes cannot be allowed during a subtree drained section, but
6
are forwarding the BDRV_REQ_NO_FALLBACK flag there, though, so this is
7
this will be fixed soon.
7
fine, too.
8
9
Declare the flag supported therefore.
10
8
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Alberto Garcia <berto@igalia.com>
15
---
10
---
16
block/qcow2.c | 3 ++-
11
include/block/block.h | 13 +++++++++++++
17
1 file changed, 2 insertions(+), 1 deletion(-)
12
block/io.c | 54 ++++++++++++++++++++++++++++++++++++++++-----------
13
2 files changed, 56 insertions(+), 11 deletions(-)
18
14
19
diff --git a/block/qcow2.c b/block/qcow2.c
15
diff --git a/include/block/block.h b/include/block/block.h
20
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.c
17
--- a/include/block/block.h
22
+++ b/block/qcow2.c
18
+++ b/include/block/block.h
23
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
19
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
24
}
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);
25
}
79
}
26
80
27
- bs->supported_zero_flags = header.version >= 3 ? BDRV_REQ_MAY_UNMAP : 0;
81
data->done = true;
28
+ bs->supported_zero_flags = header.version >= 3 ?
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
29
+ BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
83
}
30
84
31
/* Repair image if dirty */
85
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
32
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
86
- bool begin, BdrvChild *parent)
87
+ bool begin, bool recursive,
88
+ BdrvChild *parent)
89
{
90
BdrvCoDrainData data;
91
92
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
93
.bs = bs,
94
.done = false,
95
.begin = begin,
96
+ .recursive = recursive,
97
.parent = parent,
98
};
99
bdrv_inc_in_flight(bs);
100
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
101
assert(data.done);
102
}
103
104
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
105
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
106
+ BdrvChild *parent)
107
{
108
+ BdrvChild *child, *next;
109
+
110
if (qemu_in_coroutine()) {
111
- bdrv_co_yield_to_drain(bs, true, parent);
112
+ bdrv_co_yield_to_drain(bs, true, recursive, parent);
113
return;
114
}
115
116
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
117
bdrv_parent_drained_begin(bs, parent);
118
bdrv_drain_invoke(bs, true, false);
119
bdrv_drain_recurse(bs);
120
+
121
+ if (recursive) {
122
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
123
+ bdrv_do_drained_begin(child->bs, true, child);
124
+ }
125
+ }
126
}
127
128
void bdrv_drained_begin(BlockDriverState *bs)
129
{
130
- bdrv_do_drained_begin(bs, NULL);
131
+ bdrv_do_drained_begin(bs, false, NULL);
132
+}
133
+
134
+void bdrv_subtree_drained_begin(BlockDriverState *bs)
135
+{
136
+ bdrv_do_drained_begin(bs, true, NULL);
137
}
138
139
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
140
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
141
+ BdrvChild *parent)
142
{
143
+ BdrvChild *child, *next;
144
int old_quiesce_counter;
145
146
if (qemu_in_coroutine()) {
147
- bdrv_co_yield_to_drain(bs, false, parent);
148
+ bdrv_co_yield_to_drain(bs, false, recursive, parent);
149
return;
150
}
151
assert(bs->quiesce_counter > 0);
152
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
153
if (old_quiesce_counter == 1) {
154
aio_enable_external(bdrv_get_aio_context(bs));
155
}
156
+
157
+ if (recursive) {
158
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
159
+ bdrv_do_drained_end(child->bs, true, child);
160
+ }
161
+ }
162
}
163
164
void bdrv_drained_end(BlockDriverState *bs)
165
{
166
- bdrv_do_drained_end(bs, NULL);
167
+ bdrv_do_drained_end(bs, false, NULL);
168
+}
169
+
170
+void bdrv_subtree_drained_end(BlockDriverState *bs)
171
+{
172
+ bdrv_do_drained_end(bs, true, NULL);
173
}
174
175
/*
33
--
176
--
34
2.20.1
177
2.13.6
35
178
36
179
diff view generated by jsdifflib
1
Instead of having a separate blockdev_create() function, make use of the
1
Add a subtree drain version to the existing test cases.
2
VM.blockdev_create() offered by iotests.py.
3
2
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
4
---
6
tests/qemu-iotests/206 | 232 ++++++++++++++++++++---------------------
5
tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++-
7
1 file changed, 111 insertions(+), 121 deletions(-)
6
1 file changed, 26 insertions(+), 1 deletion(-)
8
7
9
diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
10
index XXXXXXX..XXXXXXX 100755
9
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/qemu-iotests/206
10
--- a/tests/test-bdrv-drain.c
12
+++ b/tests/qemu-iotests/206
11
+++ b/tests/test-bdrv-drain.c
13
@@ -XXX,XX +XXX,XX @@ from iotests import imgfmt
12
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
14
13
enum drain_type {
15
iotests.verify_image_format(supported_fmts=['qcow2'])
14
BDRV_DRAIN_ALL,
16
15
BDRV_DRAIN,
17
-def blockdev_create(vm, options):
16
+ BDRV_SUBTREE_DRAIN,
18
- result = vm.qmp_log('blockdev-create',
17
DRAIN_TYPE_MAX,
19
- filters=[iotests.filter_qmp_testfiles],
18
};
20
- job_id='job0', options=options)
19
21
-
20
@@ -XXX,XX +XXX,XX @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
22
- if 'return' in result:
21
switch (drain_type) {
23
- assert result['return'] == {}
22
case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
24
- vm.run_job('job0')
23
case BDRV_DRAIN: bdrv_drained_begin(bs); break;
25
- iotests.log("")
24
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break;
26
-
25
default: g_assert_not_reached();
27
with iotests.FilePath('t.qcow2') as disk_path, \
26
}
28
iotests.FilePath('t.qcow2.base') as backing_path, \
27
}
29
iotests.VM() as vm:
28
@@ -XXX,XX +XXX,XX @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
30
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
29
switch (drain_type) {
31
size = 128 * 1024 * 1024
30
case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
32
31
case BDRV_DRAIN: bdrv_drained_end(bs); break;
33
vm.launch()
32
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break;
34
- blockdev_create(vm, { 'driver': 'file',
33
default: g_assert_not_reached();
35
- 'filename': disk_path,
34
}
36
- 'size': 0 })
35
}
37
+ vm.blockdev_create({ 'driver': 'file',
36
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
38
+ 'filename': disk_path,
37
test_drv_cb_common(BDRV_DRAIN, false);
39
+ 'size': 0 })
38
}
40
39
41
vm.qmp_log('blockdev-add',
40
+static void test_drv_cb_drain_subtree(void)
42
filters=[iotests.filter_qmp_testfiles],
41
+{
43
driver='file', filename=disk_path,
42
+ test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
44
node_name='imgfile')
43
+}
45
46
- blockdev_create(vm, { 'driver': imgfmt,
47
- 'file': 'imgfile',
48
- 'size': size })
49
+ vm.blockdev_create({ 'driver': imgfmt,
50
+ 'file': 'imgfile',
51
+ 'size': size })
52
vm.shutdown()
53
54
iotests.img_info_log(disk_path)
55
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
56
size = 64 * 1024 * 1024
57
58
vm.launch()
59
- blockdev_create(vm, { 'driver': 'file',
60
- 'filename': disk_path,
61
- 'size': 0,
62
- 'preallocation': 'off',
63
- 'nocow': False })
64
-
65
- blockdev_create(vm, { 'driver': imgfmt,
66
- 'file': {
67
- 'driver': 'file',
68
- 'filename': disk_path,
69
- },
70
- 'size': size,
71
- 'version': 'v3',
72
- 'cluster-size': 65536,
73
- 'preallocation': 'off',
74
- 'lazy-refcounts': False,
75
- 'refcount-bits': 16 })
76
+ vm.blockdev_create({ 'driver': 'file',
77
+ 'filename': disk_path,
78
+ 'size': 0,
79
+ 'preallocation': 'off',
80
+ 'nocow': False })
81
+
44
+
82
+ vm.blockdev_create({ 'driver': imgfmt,
45
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
83
+ 'file': {
46
{
84
+ 'driver': 'file',
47
BlockBackend *blk;
85
+ 'filename': disk_path,
48
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
86
+ },
49
test_quiesce_common(BDRV_DRAIN, false);
87
+ 'size': size,
50
}
88
+ 'version': 'v3',
51
89
+ 'cluster-size': 65536,
52
+static void test_quiesce_drain_subtree(void)
90
+ 'preallocation': 'off',
53
+{
91
+ 'lazy-refcounts': False,
54
+ test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
92
+ 'refcount-bits': 16 })
55
+}
93
vm.shutdown()
94
95
iotests.img_info_log(disk_path)
96
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
97
size = 32 * 1024 * 1024
98
99
vm.launch()
100
- blockdev_create(vm, { 'driver': 'file',
101
- 'filename': disk_path,
102
- 'size': 0,
103
- 'preallocation': 'falloc',
104
- 'nocow': True })
105
-
106
- blockdev_create(vm, { 'driver': imgfmt,
107
- 'file': {
108
- 'driver': 'file',
109
- 'filename': disk_path,
110
- },
111
- 'size': size,
112
- 'version': 'v3',
113
- 'cluster-size': 2097152,
114
- 'preallocation': 'metadata',
115
- 'lazy-refcounts': True,
116
- 'refcount-bits': 1 })
117
+ vm.blockdev_create({ 'driver': 'file',
118
+ 'filename': disk_path,
119
+ 'size': 0,
120
+ 'preallocation': 'falloc',
121
+ 'nocow': True })
122
+
56
+
123
+ vm.blockdev_create({ 'driver': imgfmt,
57
static void test_nested(void)
124
+ 'file': {
58
{
125
+ 'driver': 'file',
59
BlockBackend *blk;
126
+ 'filename': disk_path,
60
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
127
+ },
61
/* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
128
+ 'size': size,
62
int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
129
+ 'version': 'v3',
63
(inner != BDRV_DRAIN_ALL);
130
+ 'cluster-size': 2097152,
64
- int backing_quiesce = 0;
131
+ 'preallocation': 'metadata',
65
+ int backing_quiesce = (outer == BDRV_SUBTREE_DRAIN) +
132
+ 'lazy-refcounts': True,
66
+ (inner == BDRV_SUBTREE_DRAIN);
133
+ 'refcount-bits': 1 })
67
int backing_cb_cnt = (outer != BDRV_DRAIN) +
134
vm.shutdown()
68
(inner != BDRV_DRAIN);
135
69
136
iotests.img_info_log(disk_path)
70
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_drain(void)
137
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
71
test_blockjob_common(BDRV_DRAIN);
138
iotests.log("")
72
}
139
73
140
vm.launch()
74
+static void test_blockjob_drain_subtree(void)
141
- blockdev_create(vm, { 'driver': 'file',
75
+{
142
- 'filename': disk_path,
76
+ test_blockjob_common(BDRV_SUBTREE_DRAIN);
143
- 'size': 0 })
77
+}
144
-
145
- blockdev_create(vm, { 'driver': imgfmt,
146
- 'file': {
147
- 'driver': 'file',
148
- 'filename': disk_path,
149
- },
150
- 'size': size,
151
- 'backing-file': backing_path,
152
- 'backing-fmt': 'qcow2',
153
- 'version': 'v2',
154
- 'cluster-size': 512 })
155
+ vm.blockdev_create({ 'driver': 'file',
156
+ 'filename': disk_path,
157
+ 'size': 0 })
158
+
78
+
159
+ vm.blockdev_create({ 'driver': imgfmt,
79
int main(int argc, char **argv)
160
+ 'file': {
80
{
161
+ 'driver': 'file',
81
bdrv_init();
162
+ 'filename': disk_path,
82
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
163
+ },
83
164
+ 'size': size,
84
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
165
+ 'backing-file': backing_path,
85
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
166
+ 'backing-fmt': 'qcow2',
86
+ g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
167
+ 'version': 'v2',
87
+ test_drv_cb_drain_subtree);
168
+ 'cluster-size': 512 })
88
169
vm.shutdown()
89
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
170
90
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
171
iotests.img_info_log(disk_path)
91
+ g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
172
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
92
+ test_quiesce_drain_subtree);
173
iotests.log("")
93
174
94
g_test_add_func("/bdrv-drain/nested", test_nested);
175
vm.launch()
95
176
- blockdev_create(vm, { 'driver': imgfmt,
96
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
177
- 'file': {
97
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
178
- 'driver': 'file',
98
+ g_test_add_func("/bdrv-drain/blockjob/drain_subtree",
179
- 'filename': disk_path,
99
+ test_blockjob_drain_subtree);
180
- },
100
181
- 'size': size,
101
return g_test_run();
182
- 'encrypt': {
102
}
183
- 'format': 'luks',
184
- 'key-secret': 'keysec0',
185
- 'cipher-alg': 'twofish-128',
186
- 'cipher-mode': 'ctr',
187
- 'ivgen-alg': 'plain64',
188
- 'ivgen-hash-alg': 'md5',
189
- 'hash-alg': 'sha1',
190
- 'iter-time': 10,
191
- }})
192
+ vm.blockdev_create({ 'driver': imgfmt,
193
+ 'file': {
194
+ 'driver': 'file',
195
+ 'filename': disk_path,
196
+ },
197
+ 'size': size,
198
+ 'encrypt': {
199
+ 'format': 'luks',
200
+ 'key-secret': 'keysec0',
201
+ 'cipher-alg': 'twofish-128',
202
+ 'cipher-mode': 'ctr',
203
+ 'ivgen-alg': 'plain64',
204
+ 'ivgen-hash-alg': 'md5',
205
+ 'hash-alg': 'sha1',
206
+ 'iter-time': 10,
207
+ }})
208
vm.shutdown()
209
210
iotests.img_info_log(disk_path)
211
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
212
iotests.log("")
213
214
vm.launch()
215
- blockdev_create(vm, { 'driver': imgfmt,
216
- 'file': "this doesn't exist",
217
- 'size': size })
218
+ vm.blockdev_create({ 'driver': imgfmt,
219
+ 'file': "this doesn't exist",
220
+ 'size': size })
221
vm.shutdown()
222
223
#
224
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
225
vm.launch()
226
for size in [ 1234, 18446744073709551104, 9223372036854775808,
227
9223372036854775296 ]:
228
- blockdev_create(vm, { 'driver': imgfmt,
229
- 'file': 'node0',
230
- 'size': size })
231
+ vm.blockdev_create({ 'driver': imgfmt,
232
+ 'file': 'node0',
233
+ 'size': size })
234
vm.shutdown()
235
236
#
237
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
238
iotests.log("=== Invalid version ===")
239
240
vm.launch()
241
- blockdev_create(vm, { 'driver': imgfmt,
242
- 'file': 'node0',
243
- 'size': 67108864,
244
- 'version': 'v1' })
245
- blockdev_create(vm, { 'driver': imgfmt,
246
- 'file': 'node0',
247
- 'size': 67108864,
248
- 'version': 'v2',
249
- 'lazy-refcounts': True })
250
- blockdev_create(vm, { 'driver': imgfmt,
251
- 'file': 'node0',
252
- 'size': 67108864,
253
- 'version': 'v2',
254
- 'refcount-bits': 8 })
255
+ vm.blockdev_create({ 'driver': imgfmt,
256
+ 'file': 'node0',
257
+ 'size': 67108864,
258
+ 'version': 'v1' })
259
+ vm.blockdev_create({ 'driver': imgfmt,
260
+ 'file': 'node0',
261
+ 'size': 67108864,
262
+ 'version': 'v2',
263
+ 'lazy-refcounts': True })
264
+ vm.blockdev_create({ 'driver': imgfmt,
265
+ 'file': 'node0',
266
+ 'size': 67108864,
267
+ 'version': 'v2',
268
+ 'refcount-bits': 8 })
269
vm.shutdown()
270
271
#
272
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
273
iotests.log("=== Invalid backing file options ===")
274
275
vm.launch()
276
- blockdev_create(vm, { 'driver': imgfmt,
277
- 'file': 'node0',
278
- 'size': 67108864,
279
- 'backing-file': '/dev/null',
280
- 'preallocation': 'full' })
281
- blockdev_create(vm, { 'driver': imgfmt,
282
- 'file': 'node0',
283
- 'size': 67108864,
284
- 'backing-fmt': imgfmt })
285
+ vm.blockdev_create({ 'driver': imgfmt,
286
+ 'file': 'node0',
287
+ 'size': 67108864,
288
+ 'backing-file': '/dev/null',
289
+ 'preallocation': 'full' })
290
+ vm.blockdev_create({ 'driver': imgfmt,
291
+ 'file': 'node0',
292
+ 'size': 67108864,
293
+ 'backing-fmt': imgfmt })
294
vm.shutdown()
295
296
#
297
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
298
299
vm.launch()
300
for csize in [ 1234, 128, 4194304, 0 ]:
301
- blockdev_create(vm, { 'driver': imgfmt,
302
- 'file': 'node0',
303
- 'size': 67108864,
304
- 'cluster-size': csize })
305
- blockdev_create(vm, { 'driver': imgfmt,
306
- 'file': 'node0',
307
- 'size': 281474976710656,
308
- 'cluster-size': 512 })
309
+ vm.blockdev_create({ 'driver': imgfmt,
310
+ 'file': 'node0',
311
+ 'size': 67108864,
312
+ 'cluster-size': csize })
313
+ vm.blockdev_create({ 'driver': imgfmt,
314
+ 'file': 'node0',
315
+ 'size': 281474976710656,
316
+ 'cluster-size': 512 })
317
vm.shutdown()
318
319
#
320
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
321
322
vm.launch()
323
for refcount_bits in [ 128, 0, 7 ]:
324
- blockdev_create(vm, { 'driver': imgfmt,
325
- 'file': 'node0',
326
- 'size': 67108864,
327
- 'refcount-bits': refcount_bits })
328
+ vm.blockdev_create({ 'driver': imgfmt,
329
+ 'file': 'node0',
330
+ 'size': 67108864,
331
+ 'refcount-bits': refcount_bits })
332
vm.shutdown()
333
--
103
--
334
2.20.1
104
2.13.6
335
105
336
106
diff view generated by jsdifflib
1
blockdev_create() is completely unused in this test case, so we can just
1
If bdrv_do_drained_begin/end() are called in coroutine context, they
2
drop it.
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.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
---
6
tests/qemu-iotests/255 | 10 ----------
7
tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
7
1 file changed, 10 deletions(-)
8
1 file changed, 59 insertions(+)
8
9
9
diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
10
index XXXXXXX..XXXXXXX 100755
11
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/qemu-iotests/255
12
--- a/tests/test-bdrv-drain.c
12
+++ b/tests/qemu-iotests/255
13
+++ b/tests/test-bdrv-drain.c
13
@@ -XXX,XX +XXX,XX @@ from iotests import imgfmt
14
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
14
15
*aio_ret = ret;
15
iotests.verify_image_format(supported_fmts=['qcow2'])
16
}
16
17
17
-def blockdev_create(vm, options):
18
+typedef struct CallInCoroutineData {
18
- result = vm.qmp_log('blockdev-create',
19
+ void (*entry)(void);
19
- filters=[iotests.filter_qmp_testfiles],
20
+ bool done;
20
- job_id='job0', options=options)
21
+} CallInCoroutineData;
21
-
22
+
22
- if 'return' in result:
23
+static coroutine_fn void call_in_coroutine_entry(void *opaque)
23
- assert result['return'] == {}
24
+{
24
- vm.run_job('job0')
25
+ CallInCoroutineData *data = opaque;
25
- iotests.log("")
26
+
26
-
27
+ data->entry();
27
iotests.log('Finishing a commit job with background reads')
28
+ data->done = true;
28
iotests.log('============================================')
29
+}
29
iotests.log('')
30
+
31
+static void call_in_coroutine(void (*entry)(void))
32
+{
33
+ Coroutine *co;
34
+ CallInCoroutineData data = {
35
+ .entry = entry,
36
+ .done = false,
37
+ };
38
+
39
+ co = qemu_coroutine_create(call_in_coroutine_entry, &data);
40
+ qemu_coroutine_enter(co);
41
+ while (!data.done) {
42
+ aio_poll(qemu_get_aio_context(), true);
43
+ }
44
+}
45
+
46
enum drain_type {
47
BDRV_DRAIN_ALL,
48
BDRV_DRAIN,
49
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_subtree(void)
50
test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
51
}
52
53
+static void test_drv_cb_co_drain(void)
54
+{
55
+ call_in_coroutine(test_drv_cb_drain);
56
+}
57
+
58
+static void test_drv_cb_co_drain_subtree(void)
59
+{
60
+ call_in_coroutine(test_drv_cb_drain_subtree);
61
+}
62
+
63
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
64
{
65
BlockBackend *blk;
66
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain_subtree(void)
67
test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
68
}
69
70
+static void test_quiesce_co_drain(void)
71
+{
72
+ call_in_coroutine(test_quiesce_drain);
73
+}
74
+
75
+static void test_quiesce_co_drain_subtree(void)
76
+{
77
+ call_in_coroutine(test_quiesce_drain_subtree);
78
+}
79
+
80
static void test_nested(void)
81
{
82
BlockBackend *blk;
83
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
84
g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
85
test_drv_cb_drain_subtree);
86
87
+ // XXX bdrv_drain_all() doesn't work in coroutine context
88
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain);
89
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree",
90
+ test_drv_cb_co_drain_subtree);
91
+
92
+
93
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
94
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
95
g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
96
test_quiesce_drain_subtree);
97
98
+ // XXX bdrv_drain_all() doesn't work in coroutine context
99
+ g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain);
100
+ g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree",
101
+ test_quiesce_co_drain_subtree);
102
+
103
g_test_add_func("/bdrv-drain/nested", test_nested);
104
105
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
30
--
106
--
31
2.20.1
107
2.13.6
32
108
33
109
diff view generated by jsdifflib
1
We have several almost identical copies of a blockdev_create() function
1
Test that drain sections are correctly propagated through the graph.
2
in different test cases. Time to create one unified function in
3
iotests.py.
4
5
To keep the diff managable, this patch only creates the function and
6
follow-up patches will convert the individual test cases.
7
2
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
4
---
10
tests/qemu-iotests/iotests.py | 16 ++++++++++++++++
5
tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 16 insertions(+)
6
1 file changed, 74 insertions(+)
12
7
13
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/iotests.py
10
--- a/tests/test-bdrv-drain.c
16
+++ b/tests/qemu-iotests/iotests.py
11
+++ b/tests/test-bdrv-drain.c
17
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
12
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
18
elif status == 'null':
13
blk_unref(blk);
19
return error
14
}
20
15
21
+ # Returns None on success, and an error string on failure
16
+static void test_multiparent(void)
22
+ def blockdev_create(self, options, job_id='job0', filters=None):
17
+{
23
+ if filters is None:
18
+ BlockBackend *blk_a, *blk_b;
24
+ filters = [filter_qmp_testfiles]
19
+ BlockDriverState *bs_a, *bs_b, *backing;
25
+ result = self.qmp_log('blockdev-create', filters=filters,
20
+ BDRVTestState *a_s, *b_s, *backing_s;
26
+ job_id=job_id, options=options)
27
+
21
+
28
+ if 'return' in result:
22
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
29
+ assert result['return'] == {}
23
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
30
+ job_result = self.run_job(job_id)
24
+ &error_abort);
31
+ else:
25
+ a_s = bs_a->opaque;
32
+ job_result = result['error']
26
+ blk_insert_bs(blk_a, bs_a, &error_abort);
33
+
27
+
34
+ log("")
28
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
35
+ return job_result
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);
36
+
33
+
37
def enable_migration_events(self, name):
34
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
38
log('Enabling migration QMP events on %s...' % name)
35
+ backing_s = backing->opaque;
39
log(self.qmp('migrate-set-capabilities', capabilities=[
36
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
37
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
38
+
39
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
40
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
41
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(a_s->drain_count, ==, 0);
43
+ g_assert_cmpint(b_s->drain_count, ==, 0);
44
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
45
+
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
47
+
48
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
49
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
50
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
51
+ g_assert_cmpint(a_s->drain_count, ==, 1);
52
+ g_assert_cmpint(b_s->drain_count, ==, 1);
53
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
54
+
55
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
56
+
57
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 2);
58
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
59
+ g_assert_cmpint(backing->quiesce_counter, ==, 2);
60
+ g_assert_cmpint(a_s->drain_count, ==, 2);
61
+ g_assert_cmpint(b_s->drain_count, ==, 2);
62
+ g_assert_cmpint(backing_s->drain_count, ==, 2);
63
+
64
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
65
+
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
69
+ g_assert_cmpint(a_s->drain_count, ==, 1);
70
+ g_assert_cmpint(b_s->drain_count, ==, 1);
71
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
72
+
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
74
+
75
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
76
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
77
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
78
+ g_assert_cmpint(a_s->drain_count, ==, 0);
79
+ g_assert_cmpint(b_s->drain_count, ==, 0);
80
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
81
+
82
+ bdrv_unref(backing);
83
+ bdrv_unref(bs_a);
84
+ bdrv_unref(bs_b);
85
+ blk_unref(blk_a);
86
+ blk_unref(blk_b);
87
+}
88
+
89
90
typedef struct TestBlockJob {
91
BlockJob common;
92
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
93
test_quiesce_co_drain_subtree);
94
95
g_test_add_func("/bdrv-drain/nested", test_nested);
96
+ g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
97
98
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
99
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
40
--
100
--
41
2.20.1
101
2.13.6
42
102
43
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: Stefan Hajnoczi <stefanha@redhat.com>
2
3
Only apply --image-opts to the topmost image when listing an entire
4
backing chain. It is incorrect to treat backing filenames as image
5
options. Assuming we have the backing chain t.IMGFMT.base <-
6
t.IMGFMT.mid <- t.IMGFMT, qemu-img info fails as follows:
7
8
$ qemu-img info --backing-chain --image-opts \
9
driver=qcow2,file.driver=file,file.filename=t.IMGFMT
10
qemu-img: Could not open 'TEST_DIR/t.IMGFMT.mid': Cannot find device=TEST_DIR/t.IMGFMT.mid nor node_name=TEST_DIR/t.IMGFMT.mid
11
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: Alberto Garcia <berto@igalia.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
2
---
17
qemu-img.c | 3 ++
3
tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
18
tests/qemu-iotests/279 | 57 ++++++++++++++++++++++++++++++++++++++
4
1 file changed, 80 insertions(+)
19
tests/qemu-iotests/279.out | 35 +++++++++++++++++++++++
20
tests/qemu-iotests/group | 1 +
21
4 files changed, 96 insertions(+)
22
create mode 100755 tests/qemu-iotests/279
23
create mode 100644 tests/qemu-iotests/279.out
24
5
25
diff --git a/qemu-img.c b/qemu-img.c
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
26
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
27
--- a/qemu-img.c
8
--- a/tests/test-bdrv-drain.c
28
+++ b/qemu-img.c
9
+++ b/tests/test-bdrv-drain.c
29
@@ -XXX,XX +XXX,XX @@ static ImageInfoList *collect_image_info_list(bool image_opts,
10
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
30
11
blk_unref(blk_b);
31
blk_unref(blk);
12
}
32
13
33
+ /* Clear parameters that only apply to the topmost image */
14
+static void test_graph_change(void)
34
filename = fmt = NULL;
15
+{
35
+ image_opts = false;
16
+ BlockBackend *blk_a, *blk_b;
17
+ BlockDriverState *bs_a, *bs_b, *backing;
18
+ BDRVTestState *a_s, *b_s, *backing_s;
36
+
19
+
37
if (chain) {
20
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
38
if (info->has_full_backing_filename) {
21
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
39
filename = info->full_backing_filename;
22
+ &error_abort);
40
diff --git a/tests/qemu-iotests/279 b/tests/qemu-iotests/279
23
+ a_s = bs_a->opaque;
41
new file mode 100755
24
+ blk_insert_bs(blk_a, bs_a, &error_abort);
42
index XXXXXXX..XXXXXXX
43
--- /dev/null
44
+++ b/tests/qemu-iotests/279
45
@@ -XXX,XX +XXX,XX @@
46
+#!/usr/bin/env bash
47
+#
48
+# Test qemu-img --backing-chain --image-opts
49
+#
50
+# Copyright (C) 2019 Red Hat, Inc.
51
+#
52
+# This program is free software; you can redistribute it and/or modify
53
+# it under the terms of the GNU General Public License as published by
54
+# the Free Software Foundation; either version 2 of the License, or
55
+# (at your option) any later version.
56
+#
57
+# This program is distributed in the hope that it will be useful,
58
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
59
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60
+# GNU General Public License for more details.
61
+#
62
+# You should have received a copy of the GNU General Public License
63
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
64
+#
65
+
25
+
66
+seq=$(basename "$0")
26
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
67
+echo "QA output created by $seq"
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);
68
+
31
+
69
+status=1    # failure is the default!
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);
70
+
35
+
71
+_cleanup()
36
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
72
+{
37
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
73
+ _cleanup_test_img
38
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
74
+ rm -f "$TEST_IMG.mid"
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);
75
+}
91
+}
76
+trap "_cleanup; exit \$status" 0 1 2 3 15
77
+
92
+
78
+# get standard environment, filters and checks
93
79
+. ./common.rc
94
typedef struct TestBlockJob {
80
+. ./common.filter
95
BlockJob common;
81
+
96
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
82
+# Backing files are required...
97
83
+_supported_fmt qcow qcow2 vmdk qed
98
g_test_add_func("/bdrv-drain/nested", test_nested);
84
+_supported_proto file
99
g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
85
+_supported_os Linux
100
+ g_test_add_func("/bdrv-drain/graph-change", test_graph_change);
86
+
101
87
+TEST_IMG="$TEST_IMG.base" _make_test_img 64M
102
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
88
+TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base"
103
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
89
+_make_test_img -b "$TEST_IMG.mid"
90
+
91
+echo
92
+echo '== qemu-img info --backing-chain =='
93
+_img_info --backing-chain | _filter_img_info
94
+
95
+echo
96
+echo '== qemu-img info --backing-chain --image-opts =='
97
+TEST_IMG="driver=qcow2,file.driver=file,file.filename=$TEST_IMG" _img_info --backing-chain --image-opts | _filter_img_info
98
+
99
+# success, all done
100
+echo "*** done"
101
+rm -f $seq.full
102
+status=0
103
diff --git a/tests/qemu-iotests/279.out b/tests/qemu-iotests/279.out
104
new file mode 100644
105
index XXXXXXX..XXXXXXX
106
--- /dev/null
107
+++ b/tests/qemu-iotests/279.out
108
@@ -XXX,XX +XXX,XX @@
109
+QA output created by 279
110
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
111
+Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
112
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
113
+
114
+== qemu-img info --backing-chain ==
115
+image: TEST_DIR/t.IMGFMT
116
+file format: IMGFMT
117
+virtual size: 64 MiB (67108864 bytes)
118
+backing file: TEST_DIR/t.IMGFMT.mid
119
+
120
+image: TEST_DIR/t.IMGFMT.mid
121
+file format: IMGFMT
122
+virtual size: 64 MiB (67108864 bytes)
123
+backing file: TEST_DIR/t.IMGFMT.base
124
+
125
+image: TEST_DIR/t.IMGFMT.base
126
+file format: IMGFMT
127
+virtual size: 64 MiB (67108864 bytes)
128
+
129
+== qemu-img info --backing-chain --image-opts ==
130
+image: TEST_DIR/t.IMGFMT
131
+file format: IMGFMT
132
+virtual size: 64 MiB (67108864 bytes)
133
+backing file: TEST_DIR/t.IMGFMT.mid
134
+
135
+image: TEST_DIR/t.IMGFMT.mid
136
+file format: IMGFMT
137
+virtual size: 64 MiB (67108864 bytes)
138
+backing file: TEST_DIR/t.IMGFMT.base
139
+
140
+image: TEST_DIR/t.IMGFMT.base
141
+file format: IMGFMT
142
+virtual size: 64 MiB (67108864 bytes)
143
+*** done
144
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
145
index XXXXXXX..XXXXXXX 100644
146
--- a/tests/qemu-iotests/group
147
+++ b/tests/qemu-iotests/group
148
@@ -XXX,XX +XXX,XX @@
149
272 rw
150
273 backing quick
151
277 rw quick
152
+279 rw backing quick
153
--
104
--
154
2.20.1
105
2.13.6
155
106
156
107
diff view generated by jsdifflib
1
The blockdev_create() function in this test case adds another filter to
1
Since commit bde70715, base is the only node that is reopened in
2
the logging, but provides otherwise the same functionality as
2
commit_start(). This means that the code, which still involves an
3
VM.blockdev_create() from iotests.py. Make it a thin wrapper around the
3
explicit BlockReopenQueue, can now be simplified by using bdrv_reopen().
4
iotests.py function.
5
4
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Fam Zheng <famz@redhat.com>
7
---
7
---
8
tests/qemu-iotests/207 | 8 +-------
8
block/commit.c | 8 +-------
9
1 file changed, 1 insertion(+), 7 deletions(-)
9
1 file changed, 1 insertion(+), 7 deletions(-)
10
10
11
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
11
diff --git a/block/commit.c b/block/commit.c
12
index XXXXXXX..XXXXXXX 100755
12
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/207
13
--- a/block/commit.c
14
+++ b/tests/qemu-iotests/207
14
+++ b/block/commit.c
15
@@ -XXX,XX +XXX,XX @@ def filter_hash(qmsg):
15
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
16
return iotests.filter_qmp(qmsg, _filter)
16
const char *filter_node_name, Error **errp)
17
17
{
18
def blockdev_create(vm, options):
18
CommitBlockJob *s;
19
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
19
- BlockReopenQueue *reopen_queue = NULL;
20
- filters=[iotests.filter_qmp_testfiles, filter_hash])
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
- }
21
-
30
-
22
- if 'return' in result:
31
- if (reopen_queue) {
23
- assert result['return'] == {}
32
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
24
- vm.run_job('job0')
33
+ bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
25
- iotests.log("")
34
if (local_err != NULL) {
26
+ vm.blockdev_create(options, filters=[iotests.filter_qmp_testfiles, filter_hash])
35
error_propagate(errp, local_err);
27
36
goto fail;
28
with iotests.FilePath('t.img') as disk_path, \
29
iotests.VM() as vm:
30
--
37
--
31
2.20.1
38
2.13.6
32
39
33
40
diff view generated by jsdifflib
1
If both the create options (qemu-img create -o ...) and the size
1
The bdrv_reopen*() implementation doesn't like it if the graph is
2
parameter were given, the size parameter was silently ignored. Instead,
2
changed between queuing nodes for reopen and actually reopening them
3
make specifying two sizes an error.
3
(one of the reasons is that queuing can be recursive).
4
5
So instead of draining the device only in bdrv_reopen_multiple(),
6
require that callers already drained all affected nodes, and assert this
7
in bdrv_reopen_queue().
4
8
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
7
---
11
---
8
block.c | 10 ++++++++--
12
block.c | 23 ++++++++++++++++-------
9
tests/qemu-iotests/049 | 5 +++++
13
block/replication.c | 6 ++++++
10
tests/qemu-iotests/049.out | 5 +++++
14
qemu-io-cmds.c | 3 +++
11
3 files changed, 18 insertions(+), 2 deletions(-)
15
3 files changed, 25 insertions(+), 7 deletions(-)
12
16
13
diff --git a/block.c b/block.c
17
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
19
--- a/block.c
16
+++ b/block.c
20
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
21
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
18
return;
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:
19
}
64
}
20
65
g_free(bs_queue);
21
+ /* Create parameter list */
66
22
create_opts = qemu_opts_append(create_opts, drv->create_opts);
67
- bdrv_drain_all_end();
23
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
68
-
24
69
return ret;
25
- /* Create parameter list with default values */
70
}
26
opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
71
27
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
72
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
28
73
{
29
/* Parse -o options */
74
int ret = -1;
30
if (options) {
75
Error *local_err = NULL;
31
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
76
- BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
32
}
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);
33
}
85
}
34
35
+ if (!qemu_opt_get(opts, BLOCK_OPT_SIZE)) {
36
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
37
+ } else if (img_size != UINT64_C(-1)) {
38
+ error_setg(errp, "The image size must be specified only once");
39
+ goto out;
40
+ }
41
+
86
+
42
if (base_filename) {
87
+ bdrv_subtree_drained_end(bs);
43
qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, &local_err);
44
if (local_err) {
45
diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049
46
index XXXXXXX..XXXXXXX 100755
47
--- a/tests/qemu-iotests/049
48
+++ b/tests/qemu-iotests/049
49
@@ -XXX,XX +XXX,XX @@ for s in $sizes; do
50
test_qemu_img create -f $IMGFMT -o size=$s "$TEST_IMG"
51
done
52
53
+echo "== 4. Specify size twice (-o and traditional parameter) =="
54
+echo
55
+
88
+
56
+test_qemu_img create -f $IMGFMT -o size=10M "$TEST_IMG" 20M
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);
57
+
102
+
58
echo "== Check correct interpretation of suffixes for cluster size =="
103
if (orig_hidden_flags != new_hidden_flags) {
59
echo
104
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
60
sizes="1024 1024b 1k 1K 1M "
105
new_hidden_flags);
61
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
106
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
107
reopen_queue, &local_err);
108
error_propagate(errp, local_err);
109
}
110
+
111
+ bdrv_subtree_drained_end(s->hidden_disk->bs);
112
+ bdrv_subtree_drained_end(s->secondary_disk->bs);
113
}
114
115
static void backup_job_cleanup(BlockDriverState *bs)
116
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
62
index XXXXXXX..XXXXXXX 100644
117
index XXXXXXX..XXXXXXX 100644
63
--- a/tests/qemu-iotests/049.out
118
--- a/qemu-io-cmds.c
64
+++ b/tests/qemu-iotests/049.out
119
+++ b/qemu-io-cmds.c
65
@@ -XXX,XX +XXX,XX @@ qemu-img: TEST_DIR/t.qcow2: Parameter 'size' expects a non-negative number below
120
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
66
Optional suffix k, M, G, T, P or E means kilo-, mega-, giga-, tera-, peta-
121
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
67
and exabytes, respectively.
122
qemu_opts_reset(&reopen_opts);
68
123
69
+== 4. Specify size twice (-o and traditional parameter) ==
124
+ bdrv_subtree_drained_begin(bs);
125
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
126
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
127
+ bdrv_subtree_drained_end(bs);
70
+
128
+
71
+qemu-img create -f qcow2 -o size=10M TEST_DIR/t.qcow2 20M
129
if (local_err) {
72
+qemu-img: TEST_DIR/t.qcow2: The image size must be specified only once
130
error_report_err(local_err);
73
+
131
} else {
74
== Check correct interpretation of suffixes for cluster size ==
75
76
qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M
77
--
132
--
78
2.20.1
133
2.13.6
79
134
80
135
diff view generated by jsdifflib