1
The following changes since commit 59a568b57848b10e8a44518a889323f12ccdd8f4:
1
The following changes since commit 281f327487c9c9b1599f93c589a408bbf4a651b8:
2
2
3
Merge remote-tracking branch 'remotes/kraxel/tags/vga-20190222-pull-request' into staging (2019-02-25 12:49:07 +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 1b967e9f348d48788a2ab481d45398b80ce71fa6:
9
for you to fetch changes up to 1a63a907507fbbcfaee3f622907ec244b7eabda8:
10
10
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2019-02-25' into queue-block (2019-02-25 15:16:57 +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
- Block graph change fixes (avoid loops, cope with non-tree graphs)
17
- bdrv_set_aio_context() related fixes
18
- HMP snapshot commands: Use only tag, not the ID to identify snapshots
19
- qmeu-img, commit: Error path fixes
20
- block/nvme: Build fix for gcc 9
21
- MAINTAINERS updates
22
- Fix various issues with bdrv_refresh_filename()
23
- Fix various iotests
24
- Include LUKS overhead in qemu-img measure for qcow2
25
- A fix for vmdk's image creation interface
26
15
27
----------------------------------------------------------------
16
----------------------------------------------------------------
28
Alberto Garcia (2):
17
Doug Gale (1):
29
commit: Replace commit_top_bs on failure after deleting the block job
18
nvme: Add tracing
30
qcow2: Assert that L2 table offsets fit in the L1 table
31
19
32
Daniel Henrique Barboza (3):
20
Edgar Kaziakhmedov (1):
33
block/snapshot.c: eliminate use of ID input in snapshot operations
21
qcow2: get rid of qcow2_backing_read1 routine
34
block/snapshot: remove bdrv_snapshot_delete_by_id_or_name
35
qcow2-snapshot: remove redundant find_snapshot_by_id_and_name call
36
22
37
Daniel P. Berrangé (1):
23
Fam Zheng (2):
38
qemu-img: fix error reporting for -object
24
block: Open backing image in force share mode for size probe
25
block: Remove unused bdrv_requests_pending
39
26
40
Denis Plotnikov (1):
27
John Snow (1):
41
block: don't set the same context
28
iotests: fix 197 for vpc
42
29
43
Jeff Cody (2):
30
Kevin Wolf (27):
44
MAINTAINERS: Replace myself with John Snow for block jobs
31
block: Formats don't need CONSISTENT_READ with NO_IO
45
MAINTAINERS: Remove myself as block maintainer
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
46
58
47
Kevin Wolf (14):
59
Thomas Huth (3):
48
block-backend: Make blk_inc/dec_in_flight public
60
block: Remove the obsolete -drive boot=on|off parameter
49
virtio-blk: Increase in_flight for request restart BH
61
block: Remove the deprecated -hdachs option
50
nbd: Restrict connection_co reentrance
62
block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter
51
io: Make qio_channel_yield() interruptible
52
io: Remove redundant read/write_coroutine assignments
53
nbd: Move nbd_read_eof() to nbd/client.c
54
nbd: Use low-level QIOChannel API in nbd_read_eof()
55
nbd: Increase bs->in_flight during AioContext switch
56
block: Don't poll in bdrv_set_aio_context()
57
block: Fix AioContext switch for drained node
58
test-bdrv-drain: AioContext switch in drained section
59
block: Use normal drain for bdrv_set_aio_context()
60
aio-posix: Assert that aio_poll() is always called in home thread
61
Merge remote-tracking branch 'mreitz/tags/pull-block-2019-02-25' into queue-block
62
63
63
Max Reitz (42):
64
qapi/block-core.json | 4 +
64
block: Use bdrv_refresh_filename() to pull
65
block/qcow2.h | 3 -
65
block: Use children list in bdrv_refresh_filename
66
include/block/block.h | 15 +-
66
block: Skip implicit nodes for filename info
67
include/block/block_int.h | 6 +-
67
block: Add BDS.auto_backing_file
68
block.c | 75 ++++-
68
block: Respect backing bs in bdrv_refresh_filename
69
block/commit.c | 8 +-
69
iotests.py: Add filter_imgfmt()
70
block/io.c | 164 +++++++---
70
iotests.py: Add node_info()
71
block/qcow2.c | 51 +--
71
iotests: Add test for backing file overrides
72
block/replication.c | 6 +
72
block: Make path_combine() return the path
73
blockdev.c | 11 -
73
block: bdrv_get_full_backing_filename_from_...'s ret. val.
74
blockjob.c | 22 +-
74
block: bdrv_get_full_backing_filename's ret. val.
75
hmp.c | 6 -
75
block: Add bdrv_make_absolute_filename()
76
hw/block/nvme.c | 349 +++++++++++++++++----
76
block: Fix bdrv_find_backing_image()
77
qemu-io-cmds.c | 3 +
77
block: Add bdrv_dirname()
78
tests/test-bdrv-drain.c | 651 +++++++++++++++++++++++++++++++++++++++
78
blkverify: Make bdrv_dirname() return NULL
79
vl.c | 86 +-----
79
quorum: Make bdrv_dirname() return NULL
80
hw/block/trace-events | 93 ++++++
80
block/nbd: Make bdrv_dirname() return NULL
81
qemu-doc.texi | 29 +-
81
block/nfs: Implement bdrv_dirname()
82
qemu-options.hx | 19 +-
82
block: Use bdrv_dirname() for relative filenames
83
tests/Makefile.include | 2 +
83
iotests: Add quorum case to test 110
84
tests/qemu-iotests/197 | 4 +
84
block: Add strong_runtime_opts to BlockDriver
85
tests/qemu-iotests/common.filter | 3 +-
85
block: Add BlockDriver.bdrv_gather_child_options
86
22 files changed, 1294 insertions(+), 316 deletions(-)
86
block: Generically refresh runtime options
87
create mode 100644 tests/test-bdrv-drain.c
87
block: Purify .bdrv_refresh_filename()
88
block: Do not copy exact_filename from format file
89
block/nvme: Fix bdrv_refresh_filename()
90
block/curl: Harmonize option defaults
91
block/curl: Implement bdrv_refresh_filename()
92
block/null: Generate filename even with latency-ns
93
block: BDS options may lack the "driver" option
94
iotests: Test json:{} filenames of internal BDSs
95
iotests: Re-add filename filters
96
iotests: Fix 237 for Python 2.x
97
iotests: Remove superfluous rm from 232
98
iotests: Fix 232 for LUKS
99
iotests: Fix 207 to use QMP filters for qmp_log
100
iotests.py: Add is_str()
101
iotests.py: Filter filename in any string value
102
iotests: Filter SSH paths
103
iotests: Let 045 be run concurrently
104
iotests.py: s/_/-/g on keys in qmp_log()
105
iotests: Skip 211 on insufficient memory
106
88
107
Stefan Hajnoczi (2):
108
qcow2: include LUKS payload overhead in qemu-img measure
109
iotests: add LUKS payload overhead to 178 qemu-img measure test
110
111
Thomas Huth (1):
112
block/nvme: Remove QEMU_PACKED from naturally aligned NVMeRegs struct
113
114
Vladimir Sementsov-Ogievskiy (3):
115
block: improve should_update_child
116
block: fix bdrv_check_perm for non-tree subgraph
117
tests: add test-bdrv-graph-mod
118
119
yuchenlin (1):
120
vmdk: false positive of compat6 with hwversion not set
121
122
block/nbd-client.h | 1 +
123
include/block/block.h | 16 +-
124
include/block/block_int.h | 53 +++-
125
include/block/nbd.h | 3 +-
126
include/block/snapshot.h | 3 -
127
include/io/channel.h | 9 +-
128
include/sysemu/block-backend.h | 2 +
129
nbd/nbd-internal.h | 19 --
130
block.c | 597 +++++++++++++++++++++++++++------------
131
block/blkdebug.c | 70 ++---
132
block/blklogwrites.c | 33 +--
133
block/blkverify.c | 29 +-
134
block/block-backend.c | 4 +-
135
block/commit.c | 7 +-
136
block/crypto.c | 8 +
137
block/curl.c | 55 +++-
138
block/gluster.c | 19 ++
139
block/iscsi.c | 18 ++
140
block/mirror.c | 3 +-
141
block/nbd-client.c | 36 ++-
142
block/nbd.c | 46 +--
143
block/nfs.c | 54 ++--
144
block/null.c | 32 ++-
145
block/nvme.c | 29 +-
146
block/qapi.c | 16 +-
147
block/qcow.c | 14 +-
148
block/qcow2-cluster.c | 3 +
149
block/qcow2-snapshot.c | 5 -
150
block/qcow2.c | 89 +++++-
151
block/qed.c | 7 +-
152
block/quorum.c | 71 +++--
153
block/raw-format.c | 11 +-
154
block/rbd.c | 14 +
155
block/replication.c | 10 +-
156
block/sheepdog.c | 12 +
157
block/snapshot.c | 25 +-
158
block/ssh.c | 12 +
159
block/throttle.c | 7 +
160
block/vhdx-log.c | 1 +
161
block/vmdk.c | 46 ++-
162
block/vpc.c | 7 +
163
block/vvfat.c | 12 +
164
block/vxhs.c | 11 +
165
blockdev.c | 8 +
166
hw/block/virtio-blk.c | 4 +
167
io/channel.c | 22 +-
168
nbd/client.c | 52 +++-
169
qemu-img.c | 64 +++--
170
tests/test-bdrv-drain.c | 32 +++
171
tests/test-bdrv-graph-mod.c | 198 +++++++++++++
172
util/aio-posix.c | 3 +-
173
MAINTAINERS | 22 +-
174
hmp-commands.hx | 32 ++-
175
scripts/qemu.py | 5 +-
176
tests/Makefile.include | 2 +
177
tests/qemu-iotests/045 | 2 +-
178
tests/qemu-iotests/051.out | 8 +-
179
tests/qemu-iotests/051.pc.out | 8 +-
180
tests/qemu-iotests/110 | 29 +-
181
tests/qemu-iotests/110.out | 9 +-
182
tests/qemu-iotests/178 | 8 +
183
tests/qemu-iotests/178.out.qcow2 | 24 ++
184
tests/qemu-iotests/206.out | 56 ++--
185
tests/qemu-iotests/207 | 10 +-
186
tests/qemu-iotests/207.out | 18 +-
187
tests/qemu-iotests/210 | 5 +-
188
tests/qemu-iotests/210.out | 28 +-
189
tests/qemu-iotests/211 | 9 +-
190
tests/qemu-iotests/211.out | 26 +-
191
tests/qemu-iotests/212 | 5 +-
192
tests/qemu-iotests/212.out | 44 +--
193
tests/qemu-iotests/213 | 5 +-
194
tests/qemu-iotests/213.out | 46 +--
195
tests/qemu-iotests/224 | 139 +++++++++
196
tests/qemu-iotests/224.out | 18 ++
197
tests/qemu-iotests/228 | 239 ++++++++++++++++
198
tests/qemu-iotests/228.out | 84 ++++++
199
tests/qemu-iotests/232 | 5 +-
200
tests/qemu-iotests/237 | 7 +-
201
tests/qemu-iotests/237.out | 54 ++--
202
tests/qemu-iotests/common.rc | 1 +
203
tests/qemu-iotests/group | 2 +
204
tests/qemu-iotests/iotests.py | 36 ++-
205
83 files changed, 2191 insertions(+), 697 deletions(-)
206
create mode 100644 tests/test-bdrv-graph-mod.c
207
create mode 100755 tests/qemu-iotests/224
208
create mode 100644 tests/qemu-iotests/224.out
209
create mode 100755 tests/qemu-iotests/228
210
create mode 100644 tests/qemu-iotests/228.out
211
diff view generated by jsdifflib
Deleted patch
1
From: Jeff Cody <jcody@redhat.com>
2
1
3
I'll not be involved with day-to-day qemu development, and John
4
Snow is a block jobs wizard. Have him take over block job
5
maintainership duties.
6
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
Acked-by: John Snow <jsnow@redhat.com>
9
Message-Id: <d56d7c6592e7d68aa72764e9616878394bffbc14.1537984851.git.jcody@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
MAINTAINERS | 4 ++--
13
1 file changed, 2 insertions(+), 2 deletions(-)
14
15
diff --git a/MAINTAINERS b/MAINTAINERS
16
index XXXXXXX..XXXXXXX 100644
17
--- a/MAINTAINERS
18
+++ b/MAINTAINERS
19
@@ -XXX,XX +XXX,XX @@ F: include/scsi/*
20
F: scsi/*
21
22
Block Jobs
23
-M: Jeff Cody <jcody@redhat.com>
24
+M: John Snow <jsnow@redhat.com>
25
L: qemu-block@nongnu.org
26
S: Supported
27
F: blockjob.c
28
@@ -XXX,XX +XXX,XX @@ F: block/commit.c
29
F: block/stream.c
30
F: block/mirror.c
31
F: qapi/job.json
32
-T: git https://github.com/codyprime/qemu-kvm-jtc.git block
33
+T: git https://github.com/jnsnow/qemu.git jobs
34
35
Block QAPI, monitor, command line
36
M: Markus Armbruster <armbru@redhat.com>
37
--
38
2.20.1
39
40
diff view generated by jsdifflib
Deleted patch
1
From: Jeff Cody <jcody@redhat.com>
2
1
3
I'll not be involved in day-to-day qemu development. Remove myself as
4
maintainer from the remainder of the network block drivers, and revert
5
them to the general block layer maintainership.
6
7
Move 'sheepdog' to the 'Odd Fixes' support level.
8
9
For VHDX, added my personal email address as a maintainer, as I can
10
answer questions or send the occassional bug fix. Leaving it as
11
'Supported', instead of 'Odd Fixes', because I think the rest of the
12
block layer maintainers and developers will upkeep it as well, if
13
needed.
14
15
Signed-off-by: Jeff Cody <jcody@redhat.com>
16
Acked-by: Max Reitz <mreitz@redhat.com>
17
Message-Id: <63e205cb84c8f0a10c1bc6d5d6856d72ceb56e41.1537984851.git.jcody@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
MAINTAINERS | 18 +++---------------
21
1 file changed, 3 insertions(+), 15 deletions(-)
22
23
diff --git a/MAINTAINERS b/MAINTAINERS
24
index XXXXXXX..XXXXXXX 100644
25
--- a/MAINTAINERS
26
+++ b/MAINTAINERS
27
@@ -XXX,XX +XXX,XX @@ F: block/vmdk.c
28
29
RBD
30
M: Josh Durgin <jdurgin@redhat.com>
31
-M: Jeff Cody <jcody@redhat.com>
32
L: qemu-block@nongnu.org
33
S: Supported
34
F: block/rbd.c
35
-T: git https://github.com/codyprime/qemu-kvm-jtc.git block
36
37
Sheepdog
38
M: Liu Yuan <namei.unix@gmail.com>
39
-M: Jeff Cody <jcody@redhat.com>
40
L: qemu-block@nongnu.org
41
-S: Supported
42
+L: sheepdog@lists.wpkg.org
43
+S: Odd Fixes
44
F: block/sheepdog.c
45
-T: git https://github.com/codyprime/qemu-kvm-jtc.git block
46
47
VHDX
48
-M: Jeff Cody <jcody@redhat.com>
49
+M: Jeff Cody <codyprime@gmail.com>
50
L: qemu-block@nongnu.org
51
S: Supported
52
F: block/vhdx*
53
-T: git https://github.com/codyprime/qemu-kvm-jtc.git block
54
55
VDI
56
M: Stefan Weil <sw@weilnetz.de>
57
@@ -XXX,XX +XXX,XX @@ F: docs/interop/nbd.txt
58
T: git https://repo.or.cz/qemu/ericb.git nbd
59
60
NFS
61
-M: Jeff Cody <jcody@redhat.com>
62
M: Peter Lieven <pl@kamp.de>
63
L: qemu-block@nongnu.org
64
S: Maintained
65
F: block/nfs.c
66
-T: git https://github.com/codyprime/qemu-kvm-jtc.git block
67
68
SSH
69
M: Richard W.M. Jones <rjones@redhat.com>
70
-M: Jeff Cody <jcody@redhat.com>
71
L: qemu-block@nongnu.org
72
S: Supported
73
F: block/ssh.c
74
-T: git https://github.com/codyprime/qemu-kvm-jtc.git block
75
76
CURL
77
-M: Jeff Cody <jcody@redhat.com>
78
L: qemu-block@nongnu.org
79
S: Supported
80
F: block/curl.c
81
-T: git https://github.com/codyprime/qemu-kvm-jtc.git block
82
83
GLUSTER
84
-M: Jeff Cody <jcody@redhat.com>
85
L: qemu-block@nongnu.org
86
S: Supported
87
F: block/gluster.c
88
-T: git https://github.com/codyprime/qemu-kvm-jtc.git block
89
90
Null Block Driver
91
M: Fam Zheng <fam@euphon.net>
92
--
93
2.20.1
94
95
diff view generated by jsdifflib
1
The explicit aio_poll() call in bdrv_set_aio_context() was added in
1
Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently
2
commit c2b6428d388 as a workaround for bdrv_drain() failing to achieve
2
in use as a mirror target. It is not enough for image formats, though,
3
to actually quiesce everything (specifically the NBD client code to
3
as these still unconditionally request BLK_PERM_CONSISTENT_READ.
4
switch AioContext).
5
4
6
Now that the NBD client has been fixed to complete this operation during
5
As this permission is geared towards whether the guest-visible data is
7
bdrv_drain(), we don't need the workaround any more.
6
consistent, and has no impact on whether the metadata is sane, and
8
7
'qemu-img info' does not read guest-visible data (except for the raw
9
It was wrong anyway: aio_poll() must always be run in the home thread of
8
format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there
10
the AioContext.
9
is not going to be any guest I/O performed, regardless of image format.
11
10
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
---
12
---
15
block.c | 4 ----
13
block.c | 6 +++++-
16
1 file changed, 4 deletions(-)
14
1 file changed, 5 insertions(+), 1 deletion(-)
17
15
18
diff --git a/block.c b/block.c
16
diff --git a/block.c b/block.c
19
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
20
--- a/block.c
18
--- a/block.c
21
+++ b/block.c
19
+++ b/block.c
22
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
20
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
23
bdrv_parent_drained_begin(bs, NULL, false);
21
assert(role == &child_backing || role == &child_file);
24
bdrv_drain(bs); /* ensure there are no in-flight requests */
22
25
23
if (!backing) {
26
- while (aio_poll(ctx, false)) {
24
+ int flags = bdrv_reopen_get_flags(reopen_queue, bs);
27
- /* wait for all bottom halves to execute */
25
+
28
- }
26
/* Apart from the modifications below, the same permissions are
29
-
27
* forwarded and left alone as for filters */
30
bdrv_detach_aio_context(bs);
28
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
31
29
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
32
/* This function executes in the old AioContext so acquire the new one in
30
31
/* bs->file always needs to be consistent because of the metadata. We
32
* can never allow other users to resize or write to it. */
33
- perm |= BLK_PERM_CONSISTENT_READ;
34
+ if (!(flags & BDRV_O_NO_IO)) {
35
+ perm |= BLK_PERM_CONSISTENT_READ;
36
+ }
37
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
38
} else {
39
/* We want consistent read from backing files if the parent needs it.
33
--
40
--
34
2.20.1
41
2.13.6
35
42
36
43
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: John Snow <jsnow@redhat.com>
2
2
3
The previous patch includes the LUKS payload overhead into the qemu-img
3
VPC has some difficulty creating geometries of particular size.
4
measure calculation for qcow2. Update qemu-iotests 178 to exercise this
4
However, we can indeed force it to use a literal one, so let's
5
new code path.
5
do that for the sake of test 197, which is testing some specific
6
offsets.
6
7
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-id: 20190218104525.23674-3-stefanha@redhat.com
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Reviewed-by: Lukáš Doktor <ldoktor@redhat.com>
12
---
13
---
13
tests/qemu-iotests/178 | 8 ++++++++
14
tests/qemu-iotests/197 | 4 ++++
14
tests/qemu-iotests/178.out.qcow2 | 24 ++++++++++++++++++++++++
15
tests/qemu-iotests/common.filter | 3 ++-
15
2 files changed, 32 insertions(+)
16
2 files changed, 6 insertions(+), 1 deletion(-)
16
17
17
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
18
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
18
index XXXXXXX..XXXXXXX 100755
19
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/qemu-iotests/178
20
--- a/tests/qemu-iotests/197
20
+++ b/tests/qemu-iotests/178
21
+++ b/tests/qemu-iotests/197
21
@@ -XXX,XX +XXX,XX @@ for ofmt in human json; do
22
@@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ==='
22
# The backing file doesn't need to exist :)
23
echo
23
$QEMU_IMG measure --output=$ofmt -o backing_file=x \
24
24
-f "$fmt" -O "$IMGFMT" "$TEST_IMG"
25
# Prep the images
25
+
26
+# VPC rounds image sizes to a specific geometry, force a specific size.
26
+ echo
27
+if [ "$IMGFMT" = "vpc" ]; then
27
+ echo "== $fmt input image and LUKS encryption =="
28
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
28
+ echo
29
+fi
29
+ $QEMU_IMG measure --output=$ofmt \
30
_make_test_img 4G
30
+ --object secret,id=sec0,data=base \
31
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
31
+ -o encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10 \
32
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
32
+ -f "$fmt" -O "$IMGFMT" "$TEST_IMG"
33
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
33
fi
34
35
echo
36
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
37
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/qemu-iotests/178.out.qcow2
35
--- a/tests/qemu-iotests/common.filter
39
+++ b/tests/qemu-iotests/178.out.qcow2
36
+++ b/tests/qemu-iotests/common.filter
40
@@ -XXX,XX +XXX,XX @@ converted image file size in bytes: 458752
37
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
41
required size: 1074135040
38
-e "s# log_size=[0-9]\\+##g" \
42
fully allocated size: 1074135040
39
-e "s# refcount_bits=[0-9]\\+##g" \
43
40
-e "s# key-secret=[a-zA-Z0-9]\\+##g" \
44
+== qcow2 input image and LUKS encryption ==
41
- -e "s# iter-time=[0-9]\\+##g"
45
+
42
+ -e "s# iter-time=[0-9]\\+##g" \
46
+required size: 2686976
43
+ -e "s# force_size=\\(on\\|off\\)##g"
47
+fully allocated size: 1076232192
48
+
49
== qcow2 input image and preallocation (human) ==
50
51
required size: 1074135040
52
@@ -XXX,XX +XXX,XX @@ converted image file size in bytes: 524288
53
required size: 1074135040
54
fully allocated size: 1074135040
55
56
+== raw input image and LUKS encryption ==
57
+
58
+required size: 2686976
59
+fully allocated size: 1076232192
60
+
61
== raw input image and preallocation (human) ==
62
63
required size: 1074135040
64
@@ -XXX,XX +XXX,XX @@ converted image file size in bytes: 458752
65
"fully-allocated": 1074135040
66
}
44
}
67
45
68
+== qcow2 input image and LUKS encryption ==
46
_filter_img_info()
69
+
70
+{
71
+ "required": 2686976,
72
+ "fully-allocated": 1076232192
73
+}
74
+
75
== qcow2 input image and preallocation (json) ==
76
77
{
78
@@ -XXX,XX +XXX,XX @@ converted image file size in bytes: 524288
79
"fully-allocated": 1074135040
80
}
81
82
+== raw input image and LUKS encryption ==
83
+
84
+{
85
+ "required": 2686976,
86
+ "fully-allocated": 1076232192
87
+}
88
+
89
== raw input image and preallocation (json) ==
90
91
{
92
--
47
--
93
2.20.1
48
2.13.6
94
49
95
50
diff view generated by jsdifflib
1
When a drained node changes its AioContext, we need to move its
1
This change separates bdrv_drain_invoke(), which calls the BlockDriver
2
aio_disable_external() to the new context, too.
2
drain callbacks, from bdrv_drain_recurse(). Instead, the function
3
performs its own recursion now.
3
4
4
Without this fix, drain_end will try to reenable the new context, which
5
One reason for this is that bdrv_drain_recurse() can be called multiple
5
has never been disabled, so an assertion failure is triggered.
6
times by bdrv_drain_all_begin(), but the callbacks may only be called
7
once. The separation is necessary to fix this bug.
6
8
9
The other reason is that we intend to go to a model where we call all
10
driver callbacks first, and only then start polling. This is not fully
11
achieved yet with this patch, as bdrv_drain_invoke() contains a
12
BDRV_POLL_WHILE() loop for the block driver callbacks, which can still
13
call callbacks for any unrelated event. It's a step in this direction
14
anyway.
15
16
Cc: qemu-stable@nongnu.org
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
19
---
10
block.c | 7 +++++++
20
block/io.c | 14 +++++++++++---
11
1 file changed, 7 insertions(+)
21
1 file changed, 11 insertions(+), 3 deletions(-)
12
22
13
diff --git a/block.c b/block.c
23
diff --git a/block/io.c b/block/io.c
14
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
25
--- a/block/io.c
16
+++ b/block.c
26
+++ b/block/io.c
17
@@ -XXX,XX +XXX,XX @@ void bdrv_detach_aio_context(BlockDriverState *bs)
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
18
bdrv_detach_aio_context(child->bs);
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);
19
}
61
}
20
62
21
+ if (bs->quiesce_counter) {
63
+ bdrv_drain_invoke(bs, true);
22
+ aio_enable_external(bs->aio_context);
64
bdrv_drain_recurse(bs, true);
23
+ }
24
bs->aio_context = NULL;
25
}
65
}
26
66
27
@@ -XXX,XX +XXX,XX @@ void bdrv_attach_aio_context(BlockDriverState *bs,
67
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
28
return;
29
}
68
}
30
69
31
+ if (bs->quiesce_counter) {
70
bdrv_parent_drained_end(bs);
32
+ aio_disable_external(new_context);
71
+ bdrv_drain_invoke(bs, false);
33
+ }
72
bdrv_drain_recurse(bs, false);
34
+
73
aio_enable_external(bdrv_get_aio_context(bs));
35
bs->aio_context = new_context;
74
}
36
75
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
37
QLIST_FOREACH(child, &bs->children, next) {
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
}
38
--
92
--
39
2.20.1
93
2.13.6
40
94
41
95
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
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.
2
4
3
VDI keeps the whole bitmap in memory, and the maximum size (which is
5
This is obviously not right and results in nodes that stay drained even
4
tested here) is 2 GB. This may not be available on all machines, and it
6
after bdrv_drain_all_end(), which calls .bdrv_co_drain_begin() once per
5
rarely is available when running a 32 bit build.
7
node.
6
8
7
Fix this by making VM.run_job() return the error string if an error
9
Fix bdrv_drain_all_begin() to call the callback only once, too.
8
occurred, and checking whether that contains "Could not allocate bmap"
9
in 211. If so, the test is skipped.
10
10
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Cc: qemu-stable@nongnu.org
12
Message-id: 20190218180646.30282-1-mreitz@redhat.com
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
14
---
17
tests/qemu-iotests/211 | 4 +++-
15
block/io.c | 3 +--
18
tests/qemu-iotests/iotests.py | 5 ++++-
16
1 file changed, 1 insertion(+), 2 deletions(-)
19
2 files changed, 7 insertions(+), 2 deletions(-)
20
17
21
diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211
18
diff --git a/block/io.c b/block/io.c
22
index XXXXXXX..XXXXXXX 100755
23
--- a/tests/qemu-iotests/211
24
+++ b/tests/qemu-iotests/211
25
@@ -XXX,XX +XXX,XX @@ def blockdev_create(vm, options):
26
27
if 'return' in result:
28
assert result['return'] == {}
29
- vm.run_job('job0')
30
+ error = vm.run_job('job0')
31
+ if error and 'Could not allocate bmap' in error:
32
+ iotests.notrun('Insufficient memory')
33
iotests.log("")
34
35
with iotests.FilePath('t.vdi') as disk_path, \
36
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
37
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/qemu-iotests/iotests.py
20
--- a/block/io.c
39
+++ b/tests/qemu-iotests/iotests.py
21
+++ b/block/io.c
40
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
22
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
41
log(result, filters, indent=indent)
23
aio_context_acquire(aio_context);
42
return result
24
bdrv_parent_drained_begin(bs);
43
25
aio_disable_external(aio_context);
44
+ # Returns None on success, and an error string on failure
26
+ bdrv_drain_invoke(bs, true);
45
def run_job(self, job, auto_finalize=True, auto_dismiss=False):
27
aio_context_release(aio_context);
46
+ error = None
28
47
while True:
29
if (!g_slist_find(aio_ctxs, aio_context)) {
48
for ev in self.get_qmp_events_filtered(wait=True):
30
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
49
if ev['event'] == 'JOB_STATUS_CHANGE':
31
aio_context_acquire(aio_context);
50
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
32
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
51
result = self.qmp('query-jobs')
33
if (aio_context == bdrv_get_aio_context(bs)) {
52
for j in result['return']:
34
- /* FIXME Calling this multiple times is wrong */
53
if j['id'] == job:
35
- bdrv_drain_invoke(bs, true);
54
+ error = j['error']
36
waited |= bdrv_drain_recurse(bs, true);
55
log('Job failed: %s' % (j['error']))
37
}
56
elif status == 'pending' and not auto_finalize:
38
}
57
self.qmp_log('job-finalize', id=job)
58
elif status == 'concluded' and not auto_dismiss:
59
self.qmp_log('job-dismiss', id=job)
60
elif status == 'null':
61
- return
62
+ return error
63
else:
64
iotests.log(ev)
65
66
--
39
--
67
2.20.1
40
2.13.6
68
41
69
42
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
This adds a test case that the BlockDriver callbacks for drain are
2
called in bdrv_drained_all_begin/end(), and that both of them are called
3
exactly once.
2
4
3
Add two tests of node graph modification.
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
9
tests/test-bdrv-drain.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++
10
tests/Makefile.include | 2 +
11
2 files changed, 139 insertions(+)
12
create mode 100644 tests/test-bdrv-drain.c
4
13
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
tests/test-bdrv-graph-mod.c | 198 ++++++++++++++++++++++++++++++++++++
9
tests/Makefile.include | 2 +
10
2 files changed, 200 insertions(+)
11
create mode 100644 tests/test-bdrv-graph-mod.c
12
13
diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
14
new file mode 100644
15
new file mode 100644
15
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
16
--- /dev/null
17
--- /dev/null
17
+++ b/tests/test-bdrv-graph-mod.c
18
+++ b/tests/test-bdrv-drain.c
18
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
19
+/*
20
+/*
20
+ * Block node graph modifications tests
21
+ * Block node draining tests
21
+ *
22
+ *
22
+ * Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved.
23
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
23
+ *
24
+ *
24
+ * This program is free software; you can redistribute it and/or modify
25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
25
+ * it under the terms of the GNU General Public License as published by
26
+ * of this software and associated documentation files (the "Software"), to deal
26
+ * the Free Software Foundation; either version 2 of the License, or
27
+ * in the Software without restriction, including without limitation the rights
27
+ * (at your option) any later version.
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:
28
+ *
31
+ *
29
+ * This program is distributed in the hope that it will be useful,
32
+ * The above copyright notice and this permission notice shall be included in
30
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
33
+ * all copies or substantial portions of the Software.
31
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
+ * GNU General Public License for more details.
33
+ *
34
+ *
34
+ * You should have received a copy of the GNU General Public License
35
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
36
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36
+ *
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.
37
+ */
42
+ */
38
+
43
+
39
+#include "qemu/osdep.h"
44
+#include "qemu/osdep.h"
45
+#include "block/block.h"
46
+#include "sysemu/block-backend.h"
40
+#include "qapi/error.h"
47
+#include "qapi/error.h"
41
+#include "block/block_int.h"
42
+#include "sysemu/block-backend.h"
43
+
48
+
44
+static BlockDriver bdrv_pass_through = {
49
+typedef struct BDRVTestState {
45
+ .format_name = "pass-through",
50
+ int drain_count;
46
+ .bdrv_child_perm = bdrv_filter_default_perms,
51
+} BDRVTestState;
52
+
53
+static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
54
+{
55
+ BDRVTestState *s = bs->opaque;
56
+ s->drain_count++;
57
+}
58
+
59
+static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
60
+{
61
+ BDRVTestState *s = bs->opaque;
62
+ s->drain_count--;
63
+}
64
+
65
+static void bdrv_test_close(BlockDriverState *bs)
66
+{
67
+ BDRVTestState *s = bs->opaque;
68
+ g_assert_cmpint(s->drain_count, >, 0);
69
+}
70
+
71
+static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
72
+ uint64_t offset, uint64_t bytes,
73
+ QEMUIOVector *qiov, int flags)
74
+{
75
+ /* We want this request to stay until the polling loop in drain waits for
76
+ * it to complete. We need to sleep a while as bdrv_drain_invoke() comes
77
+ * first and polls its result, too, but it shouldn't accidentally complete
78
+ * this request yet. */
79
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
80
+
81
+ return 0;
82
+}
83
+
84
+static BlockDriver bdrv_test = {
85
+ .format_name = "test",
86
+ .instance_size = sizeof(BDRVTestState),
87
+
88
+ .bdrv_close = bdrv_test_close,
89
+ .bdrv_co_preadv = bdrv_test_co_preadv,
90
+
91
+ .bdrv_co_drain_begin = bdrv_test_co_drain_begin,
92
+ .bdrv_co_drain_end = bdrv_test_co_drain_end,
47
+};
93
+};
48
+
94
+
49
+static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c,
95
+static void aio_ret_cb(void *opaque, int ret)
50
+ const BdrvChildRole *role,
51
+ BlockReopenQueue *reopen_queue,
52
+ uint64_t perm, uint64_t shared,
53
+ uint64_t *nperm, uint64_t *nshared)
54
+{
96
+{
55
+ *nperm = 0;
97
+ int *aio_ret = opaque;
56
+ *nshared = BLK_PERM_ALL;
98
+ *aio_ret = ret;
57
+}
99
+}
58
+
100
+
59
+static BlockDriver bdrv_no_perm = {
101
+static void test_drv_cb_drain_all(void)
60
+ .format_name = "no-perm",
102
+{
61
+ .bdrv_child_perm = no_perm_default_perms,
103
+ BlockBackend *blk;
62
+};
104
+ BlockDriverState *bs;
105
+ BDRVTestState *s;
106
+ BlockAIOCB *acb;
107
+ int aio_ret;
63
+
108
+
64
+static BlockDriverState *no_perm_node(const char *name)
109
+ QEMUIOVector qiov;
65
+{
110
+ struct iovec iov = {
66
+ return bdrv_new_open_driver(&bdrv_no_perm, name, BDRV_O_RDWR, &error_abort);
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);
67
+}
144
+}
68
+
145
+
69
+static BlockDriverState *pass_through_node(const char *name)
146
+int main(int argc, char **argv)
70
+{
71
+ return bdrv_new_open_driver(&bdrv_pass_through, name,
72
+ BDRV_O_RDWR, &error_abort);
73
+}
74
+
75
+/*
76
+ * test_update_perm_tree
77
+ *
78
+ * When checking node for a possibility to update permissions, it's subtree
79
+ * should be correctly checked too. New permissions for each node should be
80
+ * calculated and checked in context of permissions of other nodes. If we
81
+ * check new permissions of the node only in context of old permissions of
82
+ * its neighbors, we can finish up with wrong permission graph.
83
+ *
84
+ * This test firstly create the following graph:
85
+ * +--------+
86
+ * | root |
87
+ * +--------+
88
+ * |
89
+ * | perm: write, read
90
+ * | shared: except write
91
+ * v
92
+ * +-------------------+ +----------------+
93
+ * | passtrough filter |---------->| null-co node |
94
+ * +-------------------+ +----------------+
95
+ *
96
+ *
97
+ * and then, tries to append filter under node. Expected behavior: fail.
98
+ * Otherwise we'll get the following picture, with two BdrvChild'ren, having
99
+ * write permission to one node, without actually sharing it.
100
+ *
101
+ * +--------+
102
+ * | root |
103
+ * +--------+
104
+ * |
105
+ * | perm: write, read
106
+ * | shared: except write
107
+ * v
108
+ * +-------------------+
109
+ * | passtrough filter |
110
+ * +-------------------+
111
+ * | |
112
+ * perm: write, read | | perm: write, read
113
+ * shared: except write | | shared: except write
114
+ * v v
115
+ * +----------------+
116
+ * | null co node |
117
+ * +----------------+
118
+ */
119
+static void test_update_perm_tree(void)
120
+{
121
+ Error *local_err = NULL;
122
+
123
+ BlockBackend *root = blk_new(BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ,
124
+ BLK_PERM_ALL & ~BLK_PERM_WRITE);
125
+ BlockDriverState *bs = no_perm_node("node");
126
+ BlockDriverState *filter = pass_through_node("filter");
127
+
128
+ blk_insert_bs(root, bs, &error_abort);
129
+
130
+ bdrv_attach_child(filter, bs, "child", &child_file, &error_abort);
131
+
132
+ bdrv_append(filter, bs, &local_err);
133
+
134
+ g_assert_nonnull(local_err);
135
+
136
+ bdrv_unref(bs);
137
+ blk_unref(root);
138
+}
139
+
140
+/*
141
+ * test_should_update_child
142
+ *
143
+ * Test that bdrv_replace_node, and concretely should_update_child
144
+ * do the right thing, i.e. not creating loops on the graph.
145
+ *
146
+ * The test does the following:
147
+ * 1. initial graph:
148
+ *
149
+ * +------+ +--------+
150
+ * | root | | filter |
151
+ * +------+ +--------+
152
+ * | |
153
+ * root| target|
154
+ * v v
155
+ * +------+ +--------+
156
+ * | node |<---------| target |
157
+ * +------+ backing +--------+
158
+ *
159
+ * 2. Append @filter above @node. If should_update_child works correctly,
160
+ * it understands, that backing child of @target should not be updated,
161
+ * as it will create a loop on node graph. Resulting picture should
162
+ * be the left one, not the right:
163
+ *
164
+ * +------+ +------+
165
+ * | root | | root |
166
+ * +------+ +------+
167
+ * | |
168
+ * root| root|
169
+ * v v
170
+ * +--------+ target +--------+ target
171
+ * | filter |--------------+ | filter |--------------+
172
+ * +--------+ | +--------+ |
173
+ * | | | ^ v
174
+ * backing| | backing| | +--------+
175
+ * v v | +-----------| target |
176
+ * +------+ +--------+ v backing +--------+
177
+ * | node |<---------| target | +------+
178
+ * +------+ backing +--------+ | node |
179
+ * +------+
180
+ *
181
+ * (good picture) (bad picture)
182
+ *
183
+ */
184
+static void test_should_update_child(void)
185
+{
186
+ BlockBackend *root = blk_new(0, BLK_PERM_ALL);
187
+ BlockDriverState *bs = no_perm_node("node");
188
+ BlockDriverState *filter = no_perm_node("filter");
189
+ BlockDriverState *target = no_perm_node("target");
190
+
191
+ blk_insert_bs(root, bs, &error_abort);
192
+
193
+ bdrv_set_backing_hd(target, bs, &error_abort);
194
+
195
+ g_assert(target->backing->bs == bs);
196
+ bdrv_attach_child(filter, target, "target", &child_file, &error_abort);
197
+ bdrv_append(filter, bs, &error_abort);
198
+ g_assert(target->backing->bs == bs);
199
+
200
+ bdrv_unref(bs);
201
+ blk_unref(root);
202
+}
203
+
204
+int main(int argc, char *argv[])
205
+{
147
+{
206
+ bdrv_init();
148
+ bdrv_init();
207
+ qemu_init_main_loop(&error_abort);
149
+ qemu_init_main_loop(&error_abort);
208
+
150
+
209
+ g_test_init(&argc, &argv, NULL);
151
+ g_test_init(&argc, &argv, NULL);
210
+
152
+
211
+ g_test_add_func("/bdrv-graph-mod/update-perm-tree", test_update_perm_tree);
153
+ g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
212
+ g_test_add_func("/bdrv-graph-mod/should-update-child",
213
+ test_should_update_child);
214
+
154
+
215
+ return g_test_run();
155
+ return g_test_run();
216
+}
156
+}
217
diff --git a/tests/Makefile.include b/tests/Makefile.include
157
diff --git a/tests/Makefile.include b/tests/Makefile.include
218
index XXXXXXX..XXXXXXX 100644
158
index XXXXXXX..XXXXXXX 100644
219
--- a/tests/Makefile.include
159
--- a/tests/Makefile.include
220
+++ b/tests/Makefile.include
160
+++ b/tests/Makefile.include
221
@@ -XXX,XX +XXX,XX @@ check-unit-y += tests/test-throttle$(EXESUF)
161
@@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c
222
check-unit-y += tests/test-thread-pool$(EXESUF)
162
gcov-files-test-hbitmap-y = util/hbitmap.c
223
check-unit-y += tests/test-hbitmap$(EXESUF)
163
check-unit-y += tests/test-hbitmap$(EXESUF)
224
check-unit-y += tests/test-bdrv-drain$(EXESUF)
164
gcov-files-test-hbitmap-y = blockjob.c
225
+check-unit-y += tests/test-bdrv-graph-mod$(EXESUF)
165
+check-unit-y += tests/test-bdrv-drain$(EXESUF)
226
check-unit-y += tests/test-blockjob$(EXESUF)
166
check-unit-y += tests/test-blockjob$(EXESUF)
227
check-unit-y += tests/test-blockjob-txn$(EXESUF)
167
check-unit-y += tests/test-blockjob-txn$(EXESUF)
228
check-unit-y += tests/test-block-backend$(EXESUF)
168
check-unit-y += tests/test-x86-cpuid$(EXESUF)
229
@@ -XXX,XX +XXX,XX @@ tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
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)
230
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
171
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
231
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
172
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
232
tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
173
+tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
233
+tests/test-bdrv-graph-mod$(EXESUF): tests/test-bdrv-graph-mod.o $(test-block-obj-y) $(test-util-obj-y)
234
tests/test-blockjob$(EXESUF): tests/test-blockjob.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)
235
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.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)
236
tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y)
176
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
237
--
177
--
238
2.20.1
178
2.13.6
239
179
240
180
diff view generated by jsdifflib
1
qio_channel_yield() now updates ioc->read_write/coroutine and calls
1
Now that the bdrv_drain_invoke() calls are pulled up to the callers of
2
qio_channel_set_aio_fd_handlers(), so the code in the handlers has
2
bdrv_drain_recurse(), the 'begin' parameter isn't needed any more.
3
become redundant and can be removed.
4
3
5
This does not make a difference in intermediate states because
6
aio_co_wake() really enters the coroutine immediately here: These
7
handlers are never run in coroutine context, and we're in the right
8
AioContext because qio_channel_attach_aio_context() asserts that the
9
handlers are inactive.
10
11
To make these conditions more obvious, assert the right AioContext.
12
13
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
6
---
16
io/channel.c | 12 ++++++------
7
block/io.c | 12 ++++++------
17
1 file changed, 6 insertions(+), 6 deletions(-)
8
1 file changed, 6 insertions(+), 6 deletions(-)
18
9
19
diff --git a/io/channel.c b/io/channel.c
10
diff --git a/block/io.c b/block/io.c
20
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
21
--- a/io/channel.c
12
--- a/block/io.c
22
+++ b/io/channel.c
13
+++ b/block/io.c
23
@@ -XXX,XX +XXX,XX @@ off_t qio_channel_io_seek(QIOChannel *ioc,
14
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
15
}
24
}
16
}
25
17
26
18
-static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
27
-static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc);
19
+static bool bdrv_drain_recurse(BlockDriverState *bs)
28
-
29
static void qio_channel_restart_read(void *opaque)
30
{
20
{
31
QIOChannel *ioc = opaque;
21
BdrvChild *child, *tmp;
32
Coroutine *co = ioc->read_coroutine;
22
bool waited;
33
23
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
34
- ioc->read_coroutine = NULL;
24
*/
35
- qio_channel_set_aio_fd_handlers(ioc);
25
bdrv_ref(bs);
36
+ /* Assert that aio_co_wake() reenters the coroutine directly */
26
}
37
+ assert(qemu_get_current_aio_context() ==
27
- waited |= bdrv_drain_recurse(bs, begin);
38
+ qemu_coroutine_get_aio_context(co));
28
+ waited |= bdrv_drain_recurse(bs);
39
aio_co_wake(co);
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);
40
}
38
}
41
39
42
@@ -XXX,XX +XXX,XX @@ static void qio_channel_restart_write(void *opaque)
40
void bdrv_drained_end(BlockDriverState *bs)
43
QIOChannel *ioc = opaque;
41
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
44
Coroutine *co = ioc->write_coroutine;
42
45
43
bdrv_parent_drained_end(bs);
46
- ioc->write_coroutine = NULL;
44
bdrv_drain_invoke(bs, false);
47
- qio_channel_set_aio_fd_handlers(ioc);
45
- bdrv_drain_recurse(bs, false);
48
+ /* Assert that aio_co_wake() reenters the coroutine directly */
46
+ bdrv_drain_recurse(bs);
49
+ assert(qemu_get_current_aio_context() ==
47
aio_enable_external(bdrv_get_aio_context(bs));
50
+ qemu_coroutine_get_aio_context(co));
51
aio_co_wake(co);
52
}
48
}
53
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
54
--
68
--
55
2.20.1
69
2.13.6
56
70
57
71
diff view generated by jsdifflib
1
aio_poll() has an existing assertion that the function is only called
1
The device is drained, so there is no point in waiting for requests at
2
from the AioContext's home thread if blocking is allowed.
2
the end of the drained section. Remove the bdrv_drain_recurse() calls
3
there.
3
4
4
This is not enough, some handlers make assumptions about the thread they
5
The bdrv_drain_recurse() calls were introduced in commit 481cad48e5e
5
run in. Extend the assertion to non-blocking calls, too.
6
in order to call the .bdrv_co_drain_end() driver callback. This is now
7
done by a separate bdrv_drain_invoke() call.
6
8
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
12
---
10
util/aio-posix.c | 3 ++-
13
block/io.c | 2 --
11
1 file changed, 2 insertions(+), 1 deletion(-)
14
1 file changed, 2 deletions(-)
12
15
13
diff --git a/util/aio-posix.c b/util/aio-posix.c
16
diff --git a/block/io.c b/block/io.c
14
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
15
--- a/util/aio-posix.c
18
--- a/block/io.c
16
+++ b/util/aio-posix.c
19
+++ b/block/io.c
17
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
20
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
18
int64_t timeout;
21
19
int64_t start = 0;
22
bdrv_parent_drained_end(bs);
20
23
bdrv_drain_invoke(bs, false);
21
+ assert(in_aio_context_home_thread(ctx));
24
- bdrv_drain_recurse(bs);
22
+
25
aio_enable_external(bdrv_get_aio_context(bs));
23
/* aio_notify can avoid the expensive event_notifier_set if
26
}
24
* everything (file descriptors, bottom halves, timers) will
27
25
* be re-evaluated before the next blocking poll(). This is
28
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
26
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
29
aio_enable_external(aio_context);
27
* so disable the optimization now.
30
bdrv_parent_drained_end(bs);
28
*/
31
bdrv_drain_invoke(bs, false);
29
if (blocking) {
32
- bdrv_drain_recurse(bs);
30
- assert(in_aio_context_home_thread(ctx));
33
aio_context_release(aio_context);
31
atomic_add(&ctx->notify_me, 2);
32
}
34
}
33
35
34
--
36
--
35
2.20.1
37
2.13.6
36
38
37
39
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Drain requests are propagated to child nodes, parent nodes and directly
2
to the AioContext. The order in which this happened was different
3
between all combinations of drain/drain_all and begin/end.
2
4
3
Both of the defaults we currently have in the curl driver are named
5
The correct order is to keep children only drained when their parents
4
based on a slightly different schema, let's unify that and call both
6
are also drained. This means that at the start of a drained section, the
5
CURL_BLOCK_OPT_${NAME}_DEFAULT.
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.
6
10
7
While at it, we can add a macro for the third option for which a default
11
This patch changes the three other functions to follow the example of
8
exists, namely "sslverify".
12
bdrv_drained_begin(), which is the only one that got it right.
9
13
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-id: 20190201192935.18394-28-mreitz@redhat.com
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
16
---
15
block/curl.c | 13 ++++++++-----
17
block/io.c | 12 ++++++++----
16
1 file changed, 8 insertions(+), 5 deletions(-)
18
1 file changed, 8 insertions(+), 4 deletions(-)
17
19
18
diff --git a/block/curl.c b/block/curl.c
20
diff --git a/block/io.c b/block/io.c
19
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
20
--- a/block/curl.c
22
--- a/block/io.c
21
+++ b/block/curl.c
23
+++ b/block/io.c
22
@@ -XXX,XX +XXX,XX @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
24
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
23
25
return;
24
#define CURL_NUM_STATES 8
25
#define CURL_NUM_ACB 8
26
-#define READ_AHEAD_DEFAULT (256 * 1024)
27
-#define CURL_TIMEOUT_DEFAULT 5
28
#define CURL_TIMEOUT_MAX 10000
29
30
#define CURL_BLOCK_OPT_URL "url"
31
@@ -XXX,XX +XXX,XX @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
32
#define CURL_BLOCK_OPT_PROXY_USERNAME "proxy-username"
33
#define CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET "proxy-password-secret"
34
35
+#define CURL_BLOCK_OPT_READAHEAD_DEFAULT (256 * 1024)
36
+#define CURL_BLOCK_OPT_SSLVERIFY_DEFAULT true
37
+#define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5
38
+
39
struct BDRVCURLState;
40
41
static bool libcurl_initialized;
42
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
43
}
26
}
44
27
45
s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
28
+ /* Stop things in parent-to-child order */
46
- READ_AHEAD_DEFAULT);
29
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
47
+ CURL_BLOCK_OPT_READAHEAD_DEFAULT);
30
aio_disable_external(bdrv_get_aio_context(bs));
48
if ((s->readahead_size & 0x1ff) != 0) {
31
bdrv_parent_drained_begin(bs);
49
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
50
s->readahead_size);
33
return;
51
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
52
}
34
}
53
35
54
s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT,
36
- bdrv_parent_drained_end(bs);
55
- CURL_TIMEOUT_DEFAULT);
37
+ /* Re-enable things in child-to-parent order */
56
+ CURL_BLOCK_OPT_TIMEOUT_DEFAULT);
38
bdrv_drain_invoke(bs, false);
57
if (s->timeout > CURL_TIMEOUT_MAX) {
39
+ bdrv_parent_drained_end(bs);
58
error_setg(errp, "timeout parameter is too large or negative");
40
aio_enable_external(bdrv_get_aio_context(bs));
59
goto out_noclean;
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);
60
}
67
}
61
68
62
- s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
63
+ s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY,
64
+ CURL_BLOCK_OPT_SSLVERIFY_DEFAULT);
65
66
cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE);
67
cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET);
68
--
69
--
69
2.20.1
70
2.13.6
70
71
71
72
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Commit 15afd94a047 added code to acquire and release the AioContext in
2
qemuio_command(). This means that the lock is taken twice now in the
3
call path from hmp_qemu_io(). This causes BDRV_POLL_WHILE() to hang for
4
any requests issued to nodes in a non-mainloop AioContext.
2
5
3
When BDSs are created by qemu itself (e.g. as filters in block jobs),
6
Dropping the first locking from hmp_qemu_io() fixes the problem.
4
they may not have a "driver" option in their options QDict. When
5
generating a json:{} filename, however, it must always be present.
6
7
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-id: 20190201192935.18394-31-mreitz@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
10
---
12
block.c | 6 ++++++
11
hmp.c | 6 ------
13
1 file changed, 6 insertions(+)
12
1 file changed, 6 deletions(-)
14
13
15
diff --git a/block.c b/block.c
14
diff --git a/hmp.c b/hmp.c
16
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
17
--- a/block.c
16
--- a/hmp.c
18
+++ b/block.c
17
+++ b/hmp.c
19
@@ -XXX,XX +XXX,XX @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
18
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
19
{
20
BlockBackend *blk;
21
BlockBackend *local_blk = NULL;
22
- AioContext *aio_context;
23
const char* device = qdict_get_str(qdict, "device");
24
const char* command = qdict_get_str(qdict, "command");
25
Error *err = NULL;
26
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
20
}
27
}
21
}
28
}
22
29
23
+ if (!qdict_haskey(d, "driver")) {
30
- aio_context = blk_get_aio_context(blk);
24
+ /* Drivers created with bdrv_new_open_driver() may not have a
31
- aio_context_acquire(aio_context);
25
+ * @driver option. Add it here. */
32
-
26
+ qdict_put_str(d, "driver", bs->drv->format_name);
33
/*
27
+ }
34
* Notably absent: Proper permission management. This is sad, but it seems
28
+
35
* almost impossible to achieve without changing the semantics and thereby
29
return found_any;
36
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
30
}
37
*/
31
38
qemuio_command(blk, command);
39
40
- aio_context_release(aio_context);
41
-
42
fail:
43
blk_unref(local_blk);
44
hmp_handle_error(mon, &err);
32
--
45
--
33
2.20.1
46
2.13.6
34
47
35
48
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
2
2
3
This new field can be set by block drivers to list the runtime options
3
Since bdrv_co_preadv does all neccessary checks including
4
they accept that may influence the contents of the respective BDS. As of
4
reading after the end of the backing file, avoid duplication
5
a follow-up patch, this list will be used by the common
5
of verification before bdrv_co_preadv call.
6
bdrv_refresh_filename() implementation to decide which options to put
7
into BDS.full_open_options (and consequently whether a JSON filename has
8
to be created), thus freeing the drivers of having to implement that
9
logic themselves.
10
6
11
Additionally, this patch adds the field to all of the block drivers that
7
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
12
need it and sets it accordingly.
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block/qcow2.h | 3 ---
13
block/qcow2.c | 51 ++++++++-------------------------------------------
14
2 files changed, 8 insertions(+), 46 deletions(-)
13
15
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
diff --git a/block/qcow2.h b/block/qcow2.h
15
Reviewed-by: Alberto Garcia <berto@igalia.com>
16
Message-id: 20190201192935.18394-22-mreitz@redhat.com
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
include/block/block_int.h | 7 +++++++
20
block/blkdebug.c | 16 ++++++++++++++++
21
block/blklogwrites.c | 8 ++++++++
22
block/crypto.c | 8 ++++++++
23
block/curl.c | 21 +++++++++++++++++++++
24
block/gluster.c | 19 +++++++++++++++++++
25
block/iscsi.c | 18 ++++++++++++++++++
26
block/nbd.c | 14 ++++++++++++++
27
block/nfs.c | 11 +++++++++++
28
block/null.c | 9 +++++++++
29
block/nvme.c | 8 ++++++++
30
block/qcow.c | 7 +++++++
31
block/qcow2.c | 7 +++++++
32
block/quorum.c | 11 +++++++++++
33
block/raw-format.c | 10 +++++++++-
34
block/rbd.c | 14 ++++++++++++++
35
block/replication.c | 8 ++++++++
36
block/sheepdog.c | 12 ++++++++++++
37
block/ssh.c | 12 ++++++++++++
38
block/throttle.c | 7 +++++++
39
block/vpc.c | 7 +++++++
40
block/vvfat.c | 12 ++++++++++++
41
block/vxhs.c | 11 +++++++++++
42
23 files changed, 256 insertions(+), 1 deletion(-)
43
44
diff --git a/include/block/block_int.h b/include/block/block_int.h
45
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/block_int.h
18
--- a/block/qcow2.h
47
+++ b/include/block/block_int.h
19
+++ b/block/qcow2.h
48
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
20
@@ -XXX,XX +XXX,XX @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
49
void (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size);
50
void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host);
51
QLIST_ENTRY(BlockDriver) list;
52
+
53
+ /* Pointer to a NULL-terminated array of names of strong options
54
+ * that can be specified for bdrv_open(). A strong option is one
55
+ * that changes the data of a BDS.
56
+ * If this pointer is NULL, the array is considered empty.
57
+ * "filename" and "driver" are always considered strong. */
58
+ const char *const *strong_runtime_opts;
59
};
60
61
typedef struct BlockLimits {
62
diff --git a/block/blkdebug.c b/block/blkdebug.c
63
index XXXXXXX..XXXXXXX 100644
64
--- a/block/blkdebug.c
65
+++ b/block/blkdebug.c
66
@@ -XXX,XX +XXX,XX @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
67
return 0;
68
}
21
}
69
22
70
+static const char *const blkdebug_strong_runtime_opts[] = {
23
/* qcow2.c functions */
71
+ "config",
24
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
72
+ "inject-error.",
25
- int64_t sector_num, int nb_sectors);
73
+ "set-state.",
26
-
74
+ "align",
27
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
75
+ "max-transfer",
28
int refcount_order, bool generous_increase,
76
+ "opt-write-zero",
29
uint64_t *refblock_count);
77
+ "max-write-zero",
78
+ "opt-discard",
79
+ "max-discard",
80
+
81
+ NULL
82
+};
83
+
84
static BlockDriver bdrv_blkdebug = {
85
.format_name = "blkdebug",
86
.protocol_name = "blkdebug",
87
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
88
= blkdebug_debug_remove_breakpoint,
89
.bdrv_debug_resume = blkdebug_debug_resume,
90
.bdrv_debug_is_suspended = blkdebug_debug_is_suspended,
91
+
92
+ .strong_runtime_opts = blkdebug_strong_runtime_opts,
93
};
94
95
static void bdrv_blkdebug_init(void)
96
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/block/blklogwrites.c
99
+++ b/block/blklogwrites.c
100
@@ -XXX,XX +XXX,XX @@ blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
101
LOG_DISCARD_FLAG, false);
102
}
103
104
+static const char *const blk_log_writes_strong_runtime_opts[] = {
105
+ "log-append",
106
+ "log-sector-size",
107
+
108
+ NULL
109
+};
110
+
111
static BlockDriver bdrv_blk_log_writes = {
112
.format_name = "blklogwrites",
113
.instance_size = sizeof(BDRVBlkLogWritesState),
114
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blk_log_writes = {
115
.bdrv_co_block_status = bdrv_co_block_status_from_file,
116
117
.is_filter = true,
118
+ .strong_runtime_opts = blk_log_writes_strong_runtime_opts,
119
};
120
121
static void bdrv_blk_log_writes_init(void)
122
diff --git a/block/crypto.c b/block/crypto.c
123
index XXXXXXX..XXXXXXX 100644
124
--- a/block/crypto.c
125
+++ b/block/crypto.c
126
@@ -XXX,XX +XXX,XX @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
127
return spec_info;
128
}
129
130
+static const char *const block_crypto_strong_runtime_opts[] = {
131
+ BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
132
+
133
+ NULL
134
+};
135
+
136
BlockDriver bdrv_crypto_luks = {
137
.format_name = "luks",
138
.instance_size = sizeof(BlockCrypto),
139
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
140
.bdrv_getlength = block_crypto_getlength,
141
.bdrv_get_info = block_crypto_get_info_luks,
142
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
143
+
144
+ .strong_runtime_opts = block_crypto_strong_runtime_opts,
145
};
146
147
static void block_crypto_init(void)
148
diff --git a/block/curl.c b/block/curl.c
149
index XXXXXXX..XXXXXXX 100644
150
--- a/block/curl.c
151
+++ b/block/curl.c
152
@@ -XXX,XX +XXX,XX @@ static int64_t curl_getlength(BlockDriverState *bs)
153
return s->len;
154
}
155
156
+static const char *const curl_strong_runtime_opts[] = {
157
+ CURL_BLOCK_OPT_URL,
158
+ CURL_BLOCK_OPT_SSLVERIFY,
159
+ CURL_BLOCK_OPT_COOKIE,
160
+ CURL_BLOCK_OPT_COOKIE_SECRET,
161
+ CURL_BLOCK_OPT_USERNAME,
162
+ CURL_BLOCK_OPT_PASSWORD_SECRET,
163
+ CURL_BLOCK_OPT_PROXY_USERNAME,
164
+ CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET,
165
+
166
+ NULL
167
+};
168
+
169
static BlockDriver bdrv_http = {
170
.format_name = "http",
171
.protocol_name = "http",
172
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_http = {
173
174
.bdrv_detach_aio_context = curl_detach_aio_context,
175
.bdrv_attach_aio_context = curl_attach_aio_context,
176
+
177
+ .strong_runtime_opts = curl_strong_runtime_opts,
178
};
179
180
static BlockDriver bdrv_https = {
181
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_https = {
182
183
.bdrv_detach_aio_context = curl_detach_aio_context,
184
.bdrv_attach_aio_context = curl_attach_aio_context,
185
+
186
+ .strong_runtime_opts = curl_strong_runtime_opts,
187
};
188
189
static BlockDriver bdrv_ftp = {
190
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ftp = {
191
192
.bdrv_detach_aio_context = curl_detach_aio_context,
193
.bdrv_attach_aio_context = curl_attach_aio_context,
194
+
195
+ .strong_runtime_opts = curl_strong_runtime_opts,
196
};
197
198
static BlockDriver bdrv_ftps = {
199
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ftps = {
200
201
.bdrv_detach_aio_context = curl_detach_aio_context,
202
.bdrv_attach_aio_context = curl_attach_aio_context,
203
+
204
+ .strong_runtime_opts = curl_strong_runtime_opts,
205
};
206
207
static void curl_block_init(void)
208
diff --git a/block/gluster.c b/block/gluster.c
209
index XXXXXXX..XXXXXXX 100644
210
--- a/block/gluster.c
211
+++ b/block/gluster.c
212
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
213
}
214
215
216
+static const char *const gluster_strong_open_opts[] = {
217
+ GLUSTER_OPT_VOLUME,
218
+ GLUSTER_OPT_PATH,
219
+ GLUSTER_OPT_TYPE,
220
+ GLUSTER_OPT_SERVER_PATTERN,
221
+ GLUSTER_OPT_HOST,
222
+ GLUSTER_OPT_PORT,
223
+ GLUSTER_OPT_TO,
224
+ GLUSTER_OPT_IPV4,
225
+ GLUSTER_OPT_IPV6,
226
+ GLUSTER_OPT_SOCKET,
227
+
228
+ NULL
229
+};
230
+
231
static BlockDriver bdrv_gluster = {
232
.format_name = "gluster",
233
.protocol_name = "gluster",
234
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster = {
235
#endif
236
.bdrv_co_block_status = qemu_gluster_co_block_status,
237
.create_opts = &qemu_gluster_create_opts,
238
+ .strong_runtime_opts = gluster_strong_open_opts,
239
};
240
241
static BlockDriver bdrv_gluster_tcp = {
242
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_tcp = {
243
#endif
244
.bdrv_co_block_status = qemu_gluster_co_block_status,
245
.create_opts = &qemu_gluster_create_opts,
246
+ .strong_runtime_opts = gluster_strong_open_opts,
247
};
248
249
static BlockDriver bdrv_gluster_unix = {
250
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_unix = {
251
#endif
252
.bdrv_co_block_status = qemu_gluster_co_block_status,
253
.create_opts = &qemu_gluster_create_opts,
254
+ .strong_runtime_opts = gluster_strong_open_opts,
255
};
256
257
/* rdma is deprecated (actually never supported for volfile fetch).
258
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_rdma = {
259
#endif
260
.bdrv_co_block_status = qemu_gluster_co_block_status,
261
.create_opts = &qemu_gluster_create_opts,
262
+ .strong_runtime_opts = gluster_strong_open_opts,
263
};
264
265
static void bdrv_gluster_init(void)
266
diff --git a/block/iscsi.c b/block/iscsi.c
267
index XXXXXXX..XXXXXXX 100644
268
--- a/block/iscsi.c
269
+++ b/block/iscsi.c
270
@@ -XXX,XX +XXX,XX @@ static QemuOptsList iscsi_create_opts = {
271
}
272
};
273
274
+static const char *const iscsi_strong_runtime_opts[] = {
275
+ "transport",
276
+ "portal",
277
+ "target",
278
+ "user",
279
+ "password",
280
+ "password-secret",
281
+ "lun",
282
+ "initiator-name",
283
+ "header-digest",
284
+
285
+ NULL
286
+};
287
+
288
static BlockDriver bdrv_iscsi = {
289
.format_name = "iscsi",
290
.protocol_name = "iscsi",
291
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = {
292
293
.bdrv_detach_aio_context = iscsi_detach_aio_context,
294
.bdrv_attach_aio_context = iscsi_attach_aio_context,
295
+
296
+ .strong_runtime_opts = iscsi_strong_runtime_opts,
297
};
298
299
#if LIBISCSI_API_VERSION >= (20160603)
300
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iser = {
301
302
.bdrv_detach_aio_context = iscsi_detach_aio_context,
303
.bdrv_attach_aio_context = iscsi_attach_aio_context,
304
+
305
+ .strong_runtime_opts = iscsi_strong_runtime_opts,
306
};
307
#endif
308
309
diff --git a/block/nbd.c b/block/nbd.c
310
index XXXXXXX..XXXXXXX 100644
311
--- a/block/nbd.c
312
+++ b/block/nbd.c
313
@@ -XXX,XX +XXX,XX @@ static char *nbd_dirname(BlockDriverState *bs, Error **errp)
314
return NULL;
315
}
316
317
+static const char *const nbd_strong_runtime_opts[] = {
318
+ "path",
319
+ "host",
320
+ "port",
321
+ "export",
322
+ "tls-creds",
323
+ "server.",
324
+
325
+ NULL
326
+};
327
+
328
static BlockDriver bdrv_nbd = {
329
.format_name = "nbd",
330
.protocol_name = "nbd",
331
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nbd = {
332
.bdrv_refresh_filename = nbd_refresh_filename,
333
.bdrv_co_block_status = nbd_client_co_block_status,
334
.bdrv_dirname = nbd_dirname,
335
+ .strong_runtime_opts = nbd_strong_runtime_opts,
336
};
337
338
static BlockDriver bdrv_nbd_tcp = {
339
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nbd_tcp = {
340
.bdrv_refresh_filename = nbd_refresh_filename,
341
.bdrv_co_block_status = nbd_client_co_block_status,
342
.bdrv_dirname = nbd_dirname,
343
+ .strong_runtime_opts = nbd_strong_runtime_opts,
344
};
345
346
static BlockDriver bdrv_nbd_unix = {
347
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nbd_unix = {
348
.bdrv_refresh_filename = nbd_refresh_filename,
349
.bdrv_co_block_status = nbd_client_co_block_status,
350
.bdrv_dirname = nbd_dirname,
351
+ .strong_runtime_opts = nbd_strong_runtime_opts,
352
};
353
354
static void bdrv_nbd_init(void)
355
diff --git a/block/nfs.c b/block/nfs.c
356
index XXXXXXX..XXXXXXX 100644
357
--- a/block/nfs.c
358
+++ b/block/nfs.c
359
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs,
360
}
361
#endif
362
363
+static const char *nfs_strong_runtime_opts[] = {
364
+ "path",
365
+ "user",
366
+ "group",
367
+ "server.",
368
+
369
+ NULL
370
+};
371
+
372
static BlockDriver bdrv_nfs = {
373
.format_name = "nfs",
374
.protocol_name = "nfs",
375
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
376
.bdrv_refresh_filename = nfs_refresh_filename,
377
.bdrv_dirname = nfs_dirname,
378
379
+ .strong_runtime_opts = nfs_strong_runtime_opts,
380
+
381
#ifdef LIBNFS_FEATURE_PAGECACHE
382
.bdrv_co_invalidate_cache = nfs_co_invalidate_cache,
383
#endif
384
diff --git a/block/null.c b/block/null.c
385
index XXXXXXX..XXXXXXX 100644
386
--- a/block/null.c
387
+++ b/block/null.c
388
@@ -XXX,XX +XXX,XX @@ static void null_refresh_filename(BlockDriverState *bs, QDict *opts)
389
bs->full_open_options = qobject_ref(opts);
390
}
391
392
+static const char *const null_strong_runtime_opts[] = {
393
+ BLOCK_OPT_SIZE,
394
+ NULL_OPT_ZEROES,
395
+
396
+ NULL
397
+};
398
+
399
static BlockDriver bdrv_null_co = {
400
.format_name = "null-co",
401
.protocol_name = "null-co",
402
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_null_co = {
403
.bdrv_co_block_status = null_co_block_status,
404
405
.bdrv_refresh_filename = null_refresh_filename,
406
+ .strong_runtime_opts = null_strong_runtime_opts,
407
};
408
409
static BlockDriver bdrv_null_aio = {
410
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_null_aio = {
411
.bdrv_co_block_status = null_co_block_status,
412
413
.bdrv_refresh_filename = null_refresh_filename,
414
+ .strong_runtime_opts = null_strong_runtime_opts,
415
};
416
417
static void bdrv_null_init(void)
418
diff --git a/block/nvme.c b/block/nvme.c
419
index XXXXXXX..XXXXXXX 100644
420
--- a/block/nvme.c
421
+++ b/block/nvme.c
422
@@ -XXX,XX +XXX,XX @@ static void nvme_unregister_buf(BlockDriverState *bs, void *host)
423
qemu_vfio_dma_unmap(s->vfio, host);
424
}
425
426
+static const char *const nvme_strong_runtime_opts[] = {
427
+ NVME_BLOCK_OPT_DEVICE,
428
+ NVME_BLOCK_OPT_NAMESPACE,
429
+
430
+ NULL
431
+};
432
+
433
static BlockDriver bdrv_nvme = {
434
.format_name = "nvme",
435
.protocol_name = "nvme",
436
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nvme = {
437
438
.bdrv_refresh_filename = nvme_refresh_filename,
439
.bdrv_refresh_limits = nvme_refresh_limits,
440
+ .strong_runtime_opts = nvme_strong_runtime_opts,
441
442
.bdrv_detach_aio_context = nvme_detach_aio_context,
443
.bdrv_attach_aio_context = nvme_attach_aio_context,
444
diff --git a/block/qcow.c b/block/qcow.c
445
index XXXXXXX..XXXXXXX 100644
446
--- a/block/qcow.c
447
+++ b/block/qcow.c
448
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow_create_opts = {
449
}
450
};
451
452
+static const char *const qcow_strong_runtime_opts[] = {
453
+ "encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET,
454
+
455
+ NULL
456
+};
457
+
458
static BlockDriver bdrv_qcow = {
459
.format_name    = "qcow",
460
.instance_size    = sizeof(BDRVQcowState),
461
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qcow = {
462
.bdrv_get_info = qcow_get_info,
463
464
.create_opts = &qcow_create_opts,
465
+ .strong_runtime_opts = qcow_strong_runtime_opts,
466
};
467
468
static void bdrv_qcow_init(void)
469
diff --git a/block/qcow2.c b/block/qcow2.c
30
diff --git a/block/qcow2.c b/block/qcow2.c
470
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
471
--- a/block/qcow2.c
32
--- a/block/qcow2.c
472
+++ b/block/qcow2.c
33
+++ b/block/qcow2.c
473
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_create_opts = {
34
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
474
}
35
return status;
475
};
476
477
+static const char *const qcow2_strong_runtime_opts[] = {
478
+ "encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET,
479
+
480
+ NULL
481
+};
482
+
483
BlockDriver bdrv_qcow2 = {
484
.format_name = "qcow2",
485
.instance_size = sizeof(BDRVQcow2State),
486
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
487
.bdrv_inactivate = qcow2_inactivate,
488
489
.create_opts = &qcow2_create_opts,
490
+ .strong_runtime_opts = qcow2_strong_runtime_opts,
491
.bdrv_co_check = qcow2_co_check,
492
.bdrv_amend_options = qcow2_amend_options,
493
494
diff --git a/block/quorum.c b/block/quorum.c
495
index XXXXXXX..XXXXXXX 100644
496
--- a/block/quorum.c
497
+++ b/block/quorum.c
498
@@ -XXX,XX +XXX,XX @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp)
499
return NULL;
500
}
36
}
501
37
502
+static const char *const quorum_strong_runtime_opts[] = {
38
-/* handle reading after the end of the backing file */
503
+ QUORUM_OPT_VOTE_THRESHOLD,
39
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
504
+ QUORUM_OPT_BLKVERIFY,
40
- int64_t offset, int bytes)
505
+ QUORUM_OPT_REWRITE,
41
-{
506
+ QUORUM_OPT_READ_PATTERN,
42
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
507
+
43
- int n1;
508
+ NULL
44
-
509
+};
45
- if ((offset + bytes) <= bs_size) {
510
+
46
- return bytes;
511
static BlockDriver bdrv_quorum = {
47
- }
512
.format_name = "quorum",
48
-
513
49
- if (offset >= bs_size) {
514
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_quorum = {
50
- n1 = 0;
515
51
- } else {
516
.is_filter = true,
52
- n1 = bs_size - offset;
517
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
53
- }
518
+
54
-
519
+ .strong_runtime_opts = quorum_strong_runtime_opts,
55
- qemu_iovec_memset(qiov, n1, 0, bytes - n1);
520
};
56
-
521
57
- return n1;
522
static void bdrv_quorum_init(void)
58
-}
523
diff --git a/block/raw-format.c b/block/raw-format.c
59
-
524
index XXXXXXX..XXXXXXX 100644
60
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
525
--- a/block/raw-format.c
61
uint64_t bytes, QEMUIOVector *qiov,
526
+++ b/block/raw-format.c
62
int flags)
527
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
63
{
528
read_flags, write_flags);
64
BDRVQcow2State *s = bs->opaque;
529
}
65
- int offset_in_cluster, n1;
530
66
+ int offset_in_cluster;
531
+static const char *const raw_strong_runtime_opts[] = {
67
int ret;
532
+ "offset",
68
unsigned int cur_bytes; /* number of bytes in current iteration */
533
+ "size",
69
uint64_t cluster_offset = 0;
534
+
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
535
+ NULL
71
case QCOW2_CLUSTER_UNALLOCATED:
536
+};
72
537
+
73
if (bs->backing) {
538
BlockDriver bdrv_raw = {
74
- /* read from the base image */
539
.format_name = "raw",
75
- n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
540
.instance_size = sizeof(BDRVRawState),
76
- offset, cur_bytes);
541
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
77
- if (n1 > 0) {
542
.bdrv_lock_medium = &raw_lock_medium,
78
- QEMUIOVector local_qiov;
543
.bdrv_co_ioctl = &raw_co_ioctl,
79
-
544
.create_opts = &raw_create_opts,
80
- qemu_iovec_init(&local_qiov, hd_qiov.niov);
545
- .bdrv_has_zero_init = &raw_has_zero_init
81
- qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1);
546
+ .bdrv_has_zero_init = &raw_has_zero_init,
82
-
547
+ .strong_runtime_opts = raw_strong_runtime_opts,
83
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
548
};
84
- qemu_co_mutex_unlock(&s->lock);
549
85
- ret = bdrv_co_preadv(bs->backing, offset, n1,
550
static void bdrv_raw_init(void)
86
- &local_qiov, 0);
551
diff --git a/block/rbd.c b/block/rbd.c
87
- qemu_co_mutex_lock(&s->lock);
552
index XXXXXXX..XXXXXXX 100644
88
-
553
--- a/block/rbd.c
89
- qemu_iovec_destroy(&local_qiov);
554
+++ b/block/rbd.c
90
-
555
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qemu_rbd_create_opts = {
91
- if (ret < 0) {
556
}
92
- goto fail;
557
};
93
- }
558
94
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
559
+static const char *const qemu_rbd_strong_runtime_opts[] = {
95
+ qemu_co_mutex_unlock(&s->lock);
560
+ "pool",
96
+ ret = bdrv_co_preadv(bs->backing, offset, cur_bytes,
561
+ "image",
97
+ &hd_qiov, 0);
562
+ "conf",
98
+ qemu_co_mutex_lock(&s->lock);
563
+ "snapshot",
99
+ if (ret < 0) {
564
+ "user",
100
+ goto fail;
565
+ "server.",
101
}
566
+ "password-secret",
102
} else {
567
+
103
/* Note: in this case, no need to wait */
568
+ NULL
569
+};
570
+
571
static BlockDriver bdrv_rbd = {
572
.format_name = "rbd",
573
.instance_size = sizeof(BDRVRBDState),
574
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
575
#ifdef LIBRBD_SUPPORTS_INVALIDATE
576
.bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache,
577
#endif
578
+
579
+ .strong_runtime_opts = qemu_rbd_strong_runtime_opts,
580
};
581
582
static void bdrv_rbd_init(void)
583
diff --git a/block/replication.c b/block/replication.c
584
index XXXXXXX..XXXXXXX 100644
585
--- a/block/replication.c
586
+++ b/block/replication.c
587
@@ -XXX,XX +XXX,XX @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
588
aio_context_release(aio_context);
589
}
590
591
+static const char *const replication_strong_runtime_opts[] = {
592
+ REPLICATION_MODE,
593
+ REPLICATION_TOP_ID,
594
+
595
+ NULL
596
+};
597
+
598
BlockDriver bdrv_replication = {
599
.format_name = "replication",
600
.instance_size = sizeof(BDRVReplicationState),
601
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_replication = {
602
.bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter,
603
604
.has_variable_length = true,
605
+ .strong_runtime_opts = replication_strong_runtime_opts,
606
};
607
608
static void bdrv_replication_init(void)
609
diff --git a/block/sheepdog.c b/block/sheepdog.c
610
index XXXXXXX..XXXXXXX 100644
611
--- a/block/sheepdog.c
612
+++ b/block/sheepdog.c
613
@@ -XXX,XX +XXX,XX @@ static QemuOptsList sd_create_opts = {
614
}
615
};
616
617
+static const char *const sd_strong_runtime_opts[] = {
618
+ "vdi",
619
+ "snap-id",
620
+ "tag",
621
+ "server.",
622
+
623
+ NULL
624
+};
625
+
626
static BlockDriver bdrv_sheepdog = {
627
.format_name = "sheepdog",
628
.protocol_name = "sheepdog",
629
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog = {
630
.bdrv_attach_aio_context = sd_attach_aio_context,
631
632
.create_opts = &sd_create_opts,
633
+ .strong_runtime_opts = sd_strong_runtime_opts,
634
};
635
636
static BlockDriver bdrv_sheepdog_tcp = {
637
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_tcp = {
638
.bdrv_attach_aio_context = sd_attach_aio_context,
639
640
.create_opts = &sd_create_opts,
641
+ .strong_runtime_opts = sd_strong_runtime_opts,
642
};
643
644
static BlockDriver bdrv_sheepdog_unix = {
645
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_unix = {
646
.bdrv_attach_aio_context = sd_attach_aio_context,
647
648
.create_opts = &sd_create_opts,
649
+ .strong_runtime_opts = sd_strong_runtime_opts,
650
};
651
652
static void bdrv_sheepdog_init(void)
653
diff --git a/block/ssh.c b/block/ssh.c
654
index XXXXXXX..XXXXXXX 100644
655
--- a/block/ssh.c
656
+++ b/block/ssh.c
657
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
658
return ssh_grow_file(s, offset, errp);
659
}
660
661
+static const char *const ssh_strong_runtime_opts[] = {
662
+ "host",
663
+ "port",
664
+ "path",
665
+ "user",
666
+ "host_key_check",
667
+ "server.",
668
+
669
+ NULL
670
+};
671
+
672
static BlockDriver bdrv_ssh = {
673
.format_name = "ssh",
674
.protocol_name = "ssh",
675
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ssh = {
676
.bdrv_co_truncate = ssh_co_truncate,
677
.bdrv_co_flush_to_disk = ssh_co_flush,
678
.create_opts = &ssh_create_opts,
679
+ .strong_runtime_opts = ssh_strong_runtime_opts,
680
};
681
682
static void bdrv_ssh_init(void)
683
diff --git a/block/throttle.c b/block/throttle.c
684
index XXXXXXX..XXXXXXX 100644
685
--- a/block/throttle.c
686
+++ b/block/throttle.c
687
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
688
atomic_dec(&tgm->io_limits_disabled);
689
}
690
691
+static const char *const throttle_strong_runtime_opts[] = {
692
+ QEMU_OPT_THROTTLE_GROUP_NAME,
693
+
694
+ NULL
695
+};
696
+
697
static BlockDriver bdrv_throttle = {
698
.format_name = "throttle",
699
.instance_size = sizeof(ThrottleGroupMember),
700
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_throttle = {
701
.bdrv_co_drain_end = throttle_co_drain_end,
702
703
.is_filter = true,
704
+ .strong_runtime_opts = throttle_strong_runtime_opts,
705
};
706
707
static void bdrv_throttle_init(void)
708
diff --git a/block/vpc.c b/block/vpc.c
709
index XXXXXXX..XXXXXXX 100644
710
--- a/block/vpc.c
711
+++ b/block/vpc.c
712
@@ -XXX,XX +XXX,XX @@ static QemuOptsList vpc_create_opts = {
713
}
714
};
715
716
+static const char *const vpc_strong_runtime_opts[] = {
717
+ VPC_OPT_SIZE_CALC,
718
+
719
+ NULL
720
+};
721
+
722
static BlockDriver bdrv_vpc = {
723
.format_name = "vpc",
724
.instance_size = sizeof(BDRVVPCState),
725
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vpc = {
726
727
.create_opts = &vpc_create_opts,
728
.bdrv_has_zero_init = vpc_has_zero_init,
729
+ .strong_runtime_opts = vpc_strong_runtime_opts,
730
};
731
732
static void bdrv_vpc_init(void)
733
diff --git a/block/vvfat.c b/block/vvfat.c
734
index XXXXXXX..XXXXXXX 100644
735
--- a/block/vvfat.c
736
+++ b/block/vvfat.c
737
@@ -XXX,XX +XXX,XX @@ static void vvfat_close(BlockDriverState *bs)
738
}
739
}
740
741
+static const char *const vvfat_strong_runtime_opts[] = {
742
+ "dir",
743
+ "fat-type",
744
+ "floppy",
745
+ "label",
746
+ "rw",
747
+
748
+ NULL
749
+};
750
+
751
static BlockDriver bdrv_vvfat = {
752
.format_name = "vvfat",
753
.protocol_name = "fat",
754
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vvfat = {
755
.bdrv_co_preadv = vvfat_co_preadv,
756
.bdrv_co_pwritev = vvfat_co_pwritev,
757
.bdrv_co_block_status = vvfat_co_block_status,
758
+
759
+ .strong_runtime_opts = vvfat_strong_runtime_opts,
760
};
761
762
static void bdrv_vvfat_init(void)
763
diff --git a/block/vxhs.c b/block/vxhs.c
764
index XXXXXXX..XXXXXXX 100644
765
--- a/block/vxhs.c
766
+++ b/block/vxhs.c
767
@@ -XXX,XX +XXX,XX @@ static int64_t vxhs_getlength(BlockDriverState *bs)
768
return vdisk_size;
769
}
770
771
+static const char *const vxhs_strong_runtime_opts[] = {
772
+ VXHS_OPT_VDISK_ID,
773
+ "tls-creds",
774
+ VXHS_OPT_HOST,
775
+ VXHS_OPT_PORT,
776
+ VXHS_OPT_SERVER".",
777
+
778
+ NULL
779
+};
780
+
781
static BlockDriver bdrv_vxhs = {
782
.format_name = "vxhs",
783
.protocol_name = "vxhs",
784
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vxhs = {
785
.bdrv_getlength = vxhs_getlength,
786
.bdrv_aio_preadv = vxhs_aio_preadv,
787
.bdrv_aio_pwritev = vxhs_aio_pwritev,
788
+ .strong_runtime_opts = vxhs_strong_runtime_opts,
789
};
790
791
static void bdrv_vxhs_init(void)
792
--
104
--
793
2.20.1
105
2.13.6
794
106
795
107
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@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
With IMGOPTSSYNTAX, $TEST_IMG is useless for this test (it only tests
6
Document this problem so that we won't accidentally mark the command
4
the file-posix protocol driver). Therefore, if $TEST_IMG_FILE is set,
7
stable without having addressed it.
5
use that instead.
6
8
7
Because this test requires the file protocol, $TEST_IMG_FILE will always
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
be set if $IMGOPTSSYNTAX is true.
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: John Snow <jsnow@redhat.com>
12
Message-id: 20190210145736.1486-5-mreitz@redhat.com
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
11
---
15
tests/qemu-iotests/232 | 4 ++++
12
qapi/block-core.json | 4 ++++
16
1 file changed, 4 insertions(+)
13
1 file changed, 4 insertions(+)
17
14
18
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
19
index XXXXXXX..XXXXXXX 100755
16
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/232
17
--- a/qapi/block-core.json
21
+++ b/tests/qemu-iotests/232
18
+++ b/qapi/block-core.json
22
@@ -XXX,XX +XXX,XX @@ size=128M
19
@@ -XXX,XX +XXX,XX @@
23
20
# does not support all kinds of operations, all kinds of children, nor
24
_make_test_img $size
21
# all block drivers.
25
22
#
26
+if [ -n "$TEST_IMG_FILE" ]; then
23
+# FIXME Removing children from a quorum node means introducing gaps in the
27
+ TEST_IMG=$TEST_IMG_FILE
24
+# child indices. This cannot be represented in the 'children' list of
28
+fi
25
+# BlockdevOptionsQuorum, as returned by .bdrv_refresh_filename().
29
+
26
+#
30
echo
27
# Warning: The data in a new quorum child MUST be consistent with that of
31
echo "=== -drive with read-write image: read-only/auto-read-only combinations ==="
28
# the rest of the array.
32
echo
29
#
33
--
30
--
34
2.20.1
31
2.13.6
35
32
36
33
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Doug Gale <doug16k@gmail.com>
2
2
3
bdrv_refresh_filename() should invoke itself recursively on all
3
Add trace output for commands, errors, and undefined behavior.
4
children, not just on file.
4
Add guest error log output for undefined behavior.
5
Report invalid undefined accesses to MMIO.
6
Annotate unlikely error checks with unlikely.
5
7
6
With that change, we can remove the manual invocations in blkverify,
8
Signed-off-by: Doug Gale <doug16k@gmail.com>
7
quorum, commit, mirror, and blklogwrites.
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
hw/block/nvme.c | 349 ++++++++++++++++++++++++++++++++++++++++++--------
14
hw/block/trace-events | 93 ++++++++++++++
15
2 files changed, 390 insertions(+), 52 deletions(-)
8
16
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Message-id: 20190201192935.18394-3-mreitz@redhat.com
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block.c | 9 +++++----
16
block/blklogwrites.c | 3 ---
17
block/blkverify.c | 3 ---
18
block/commit.c | 1 -
19
block/mirror.c | 1 -
20
block/quorum.c | 1 -
21
6 files changed, 5 insertions(+), 13 deletions(-)
22
23
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
25
--- a/block.c
19
--- a/hw/block/nvme.c
26
+++ b/block.c
20
+++ b/hw/block/nvme.c
27
@@ -XXX,XX +XXX,XX @@ static bool append_open_options(QDict *d, BlockDriverState *bs)
21
@@ -XXX,XX +XXX,XX @@
28
void bdrv_refresh_filename(BlockDriverState *bs)
22
#include "qapi/visitor.h"
23
#include "sysemu/block-backend.h"
24
25
+#include "qemu/log.h"
26
+#include "trace.h"
27
#include "nvme.h"
28
29
+#define NVME_GUEST_ERR(trace, fmt, ...) \
30
+ do { \
31
+ (trace_##trace)(__VA_ARGS__); \
32
+ qemu_log_mask(LOG_GUEST_ERROR, #trace \
33
+ " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
34
+ } while (0)
35
+
36
static void nvme_process_sq(void *opaque);
37
38
static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
39
@@ -XXX,XX +XXX,XX @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
29
{
40
{
30
BlockDriver *drv = bs->drv;
41
if (cq->irq_enabled) {
31
+ BdrvChild *child;
42
if (msix_enabled(&(n->parent_obj))) {
32
QDict *opts;
43
+ trace_nvme_irq_msix(cq->vector);
33
44
msix_notify(&(n->parent_obj), cq->vector);
34
if (!drv) {
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);
35
return;
619
return;
36
}
620
}
37
621
38
- /* This BDS's file name will most probably depend on its file's name, so
622
if (((addr - 0x1000) >> 2) & 1) {
39
- * refresh that first */
623
+ /* Completion queue doorbell write */
40
- if (bs->file) {
624
+
41
- bdrv_refresh_filename(bs->file->bs);
625
uint16_t new_head = val & 0xffff;
42
+ /* This BDS's file name may depend on any of its children's file names, so
626
int start_sqs;
43
+ * refresh those first */
627
NvmeCQueue *cq;
44
+ QLIST_FOREACH(child, &bs->children, next) {
628
45
+ bdrv_refresh_filename(child->bs);
629
qid = (addr - (0x1000 + (1 << 2))) >> 3;
46
}
630
- if (nvme_check_cqid(n, qid)) {
47
631
+ if (unlikely(nvme_check_cqid(n, qid))) {
48
if (drv->bdrv_refresh_filename) {
632
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq,
49
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
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
50
index XXXXXXX..XXXXXXX 100644
681
index XXXXXXX..XXXXXXX 100644
51
--- a/block/blklogwrites.c
682
--- a/hw/block/trace-events
52
+++ b/block/blklogwrites.c
683
+++ b/hw/block/trace-events
53
@@ -XXX,XX +XXX,XX @@ static void blk_log_writes_refresh_filename(BlockDriverState *bs,
684
@@ -XXX,XX +XXX,XX @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6
54
{
685
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
55
BDRVBlkLogWritesState *s = bs->opaque;
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"
56
687
57
- /* bs->file->bs has already been refreshed */
688
+# hw/block/nvme.c
58
- bdrv_refresh_filename(s->log_file->bs);
689
+# nvme traces for successful events
59
-
690
+nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
60
if (bs->file->bs->full_open_options
691
+nvme_irq_pin(void) "pulsing IRQ pin"
61
&& s->log_file->bs->full_open_options)
692
+nvme_irq_masked(void) "IRQ is masked"
62
{
693
+nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
63
diff --git a/block/blkverify.c b/block/blkverify.c
694
+nvme_rw(char const *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
64
index XXXXXXX..XXXXXXX 100644
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""
65
--- a/block/blkverify.c
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"
66
+++ b/block/blkverify.c
697
+nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
67
@@ -XXX,XX +XXX,XX @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
698
+nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16""
68
{
699
+nvme_identify_ctrl(void) "identify controller"
69
BDRVBlkverifyState *s = bs->opaque;
700
+nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
70
701
+nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
71
- /* bs->file->bs has already been refreshed */
702
+nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s"
72
- bdrv_refresh_filename(s->test_file->bs);
703
+nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
73
-
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"
74
if (bs->file->bs->full_open_options
705
+nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
75
&& s->test_file->bs->full_open_options)
706
+nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
76
{
707
+nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
77
diff --git a/block/commit.c b/block/commit.c
708
+nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
78
index XXXXXXX..XXXXXXX 100644
709
+nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
79
--- a/block/commit.c
710
+nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
80
+++ b/block/commit.c
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""
81
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
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""
82
713
+nvme_mmio_start_success(void) "setting controller enable bit succeeded"
83
static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *opts)
714
+nvme_mmio_stopped(void) "cleared controller enable bit"
84
{
715
+nvme_mmio_shutdown_set(void) "shutdown bit set"
85
- bdrv_refresh_filename(bs->backing->bs);
716
+nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
86
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
717
+
87
bs->backing->bs->filename);
718
+# nvme traces for error conditions
88
}
719
+nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
89
diff --git a/block/mirror.c b/block/mirror.c
720
+nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
90
index XXXXXXX..XXXXXXX 100644
721
+nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
91
--- a/block/mirror.c
722
+nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
92
+++ b/block/mirror.c
723
+nvme_err_invalid_field(void) "invalid field"
93
@@ -XXX,XX +XXX,XX @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
724
+nvme_err_invalid_prp(void) "invalid PRP"
94
* bdrv_set_backing_hd */
725
+nvme_err_invalid_sgl(void) "invalid SGL"
95
return;
726
+nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u"
96
}
727
+nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
97
- bdrv_refresh_filename(bs->backing->bs);
728
+nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
98
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
729
+nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
99
bs->backing->bs->filename);
730
+nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
100
}
731
+nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
101
diff --git a/block/quorum.c b/block/quorum.c
732
+nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
102
index XXXXXXX..XXXXXXX 100644
733
+nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
103
--- a/block/quorum.c
734
+nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
104
+++ b/block/quorum.c
735
+nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
105
@@ -XXX,XX +XXX,XX @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
736
+nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
106
int i;
737
+nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
107
738
+nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
108
for (i = 0; i < s->num_children; i++) {
739
+nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
109
- bdrv_refresh_filename(s->children[i]->bs);
740
+nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
110
if (!s->children[i]->bs->full_open_options) {
741
+nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
111
return;
742
+nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
112
}
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"
113
--
784
--
114
2.20.1
785
2.13.6
115
786
116
787
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
As it already said in the comment, we don't want to create loops in
3
Management tools create overlays of running guests with qemu-img:
4
parent->child relations. So, when we try to append @to to @c, we should
5
check that @c is not in @to children subtree, and we should check it
6
recursively, not only the first level. The patch provides BFS-based
7
search, to check the relations.
8
4
9
This is needed for further fleecing-hook filter usage: we need to
5
$ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2
10
append it to source, when the hook is already a parent of target, and
11
source may be in a backing chain of target (fleecing-scheme). So, on
12
appending, the hook should not became a child (direct or through
13
children subtree) of the target.
14
6
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.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>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
---
18
block.c | 43 +++++++++++++++++++++++++++++++++++++------
19
block.c | 3 ++-
19
1 file changed, 37 insertions(+), 6 deletions(-)
20
1 file changed, 2 insertions(+), 1 deletion(-)
20
21
21
diff --git a/block.c b/block.c
22
diff --git a/block.c b/block.c
22
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
23
--- a/block.c
24
--- a/block.c
24
+++ b/block.c
25
+++ b/block.c
25
@@ -XXX,XX +XXX,XX @@ void bdrv_close_all(void)
26
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
26
27
back_flags = flags;
27
static bool should_update_child(BdrvChild *c, BlockDriverState *to)
28
back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
28
{
29
29
- BdrvChild *to_c;
30
+ backing_options = qdict_new();
30
+ GQueue *queue;
31
if (backing_fmt) {
31
+ GHashTable *found;
32
- backing_options = qdict_new();
32
+ bool ret;
33
qdict_put_str(backing_options, "driver", backing_fmt);
33
34
if (c->role->stay_at_node) {
35
return false;
36
@@ -XXX,XX +XXX,XX @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
37
* if A is a child of B, that means we cannot replace A by B there
38
* because that would create a loop. Silently detaching A from B
39
* is also not really an option. So overall just leaving A in
40
- * place there is the most sensible choice. */
41
- QLIST_FOREACH(to_c, &to->children, next) {
42
- if (to_c == c) {
43
- return false;
44
+ * place there is the most sensible choice.
45
+ *
46
+ * We would also create a loop in any cases where @c is only
47
+ * indirectly referenced by @to. Prevent this by returning false
48
+ * if @c is found (by breadth-first search) anywhere in the whole
49
+ * subtree of @to.
50
+ */
51
+
52
+ ret = true;
53
+ found = g_hash_table_new(NULL, NULL);
54
+ g_hash_table_add(found, to);
55
+ queue = g_queue_new();
56
+ g_queue_push_tail(queue, to);
57
+
58
+ while (!g_queue_is_empty(queue)) {
59
+ BlockDriverState *v = g_queue_pop_head(queue);
60
+ BdrvChild *c2;
61
+
62
+ QLIST_FOREACH(c2, &v->children, next) {
63
+ if (c2 == c) {
64
+ ret = false;
65
+ break;
66
+ }
67
+
68
+ if (g_hash_table_contains(found, c2->bs)) {
69
+ continue;
70
+ }
71
+
72
+ g_queue_push_tail(queue, c2->bs);
73
+ g_hash_table_add(found, c2->bs);
74
}
34
}
75
}
35
+ qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true);
76
36
77
- return true;
37
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
78
+ g_queue_free(queue);
38
&local_err);
79
+ g_hash_table_destroy(found);
80
+
81
+ return ret;
82
}
83
84
void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
85
--
39
--
86
2.20.1
40
2.13.6
87
41
88
42
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Before this patch, bdrv_refresh_filename() is used in a pushing manner:
3
It's not working anymore since QEMU v1.3.0 - time to remove it now.
4
Whenever the BDS graph is modified, the parents of the modified edges
5
are supposed to be updated (recursively upwards). However, that is
6
nonviable, considering that we want child changes not to concern
7
parents.
8
4
9
Also, in the long run we want a pull model anyway: Here, we would have a
5
Signed-off-by: Thomas Huth <thuth@redhat.com>
10
bdrv_filename() function which returns a BDS's filename, freshly
6
Reviewed-by: John Snow <jsnow@redhat.com>
11
constructed.
7
Reviewed-by: Markus Armbruster <armbru@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
blockdev.c | 11 -----------
11
qemu-doc.texi | 6 ------
12
2 files changed, 17 deletions(-)
12
13
13
This patch is an intermediate step. It adds bdrv_refresh_filename()
14
calls before every place a BDS.filename value is used. The only
15
exceptions are protocol drivers that use their own filename, which
16
clearly would not profit from refreshing that filename before.
17
18
Also, bdrv_get_encrypted_filename() is removed along the way (as a user
19
of BDS.filename), since it is completely unused.
20
21
In turn, all of the calls to bdrv_refresh_filename() before this patch
22
are removed, because we no longer have to call this function on graph
23
changes.
24
25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26
Message-id: 20190201192935.18394-2-mreitz@redhat.com
27
Reviewed-by: Eric Blake <eblake@redhat.com>
28
Signed-off-by: Max Reitz <mreitz@redhat.com>
29
---
30
include/block/block.h | 1 -
31
block.c | 31 +++++++++++++++----------------
32
block/qapi.c | 4 ++++
33
block/raw-format.c | 1 +
34
block/replication.c | 2 --
35
block/vhdx-log.c | 1 +
36
block/vmdk.c | 6 ++++++
37
blockdev.c | 8 ++++++++
38
qemu-img.c | 11 +++++++++--
39
9 files changed, 44 insertions(+), 21 deletions(-)
40
41
diff --git a/include/block/block.h b/include/block/block.h
42
index XXXXXXX..XXXXXXX 100644
43
--- a/include/block/block.h
44
+++ b/include/block/block.h
45
@@ -XXX,XX +XXX,XX @@ void bdrv_round_to_clusters(BlockDriverState *bs,
46
int64_t *cluster_offset,
47
int64_t *cluster_bytes);
48
49
-const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
50
void bdrv_get_backing_filename(BlockDriverState *bs,
51
char *filename, int filename_size);
52
void bdrv_get_full_backing_filename(BlockDriverState *bs,
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 @@ void bdrv_get_full_backing_filename_from_filename(const char *backed,
58
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
59
Error **errp)
60
{
61
- char *backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
62
+ char *backed;
63
64
+ bdrv_refresh_filename(bs);
65
+
66
+ backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
67
bdrv_get_full_backing_filename_from_filename(backed, bs->backing_file,
68
dest, sz, errp);
69
}
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_attach(BdrvChild *c)
71
"node is used as backing hd of '%s'",
72
bdrv_get_device_or_node_name(parent));
73
74
+ bdrv_refresh_filename(backing_hd);
75
+
76
parent->open_flags &= ~BDRV_O_NO_BACKING;
77
pstrcpy(parent->backing_file, sizeof(parent->backing_file),
78
backing_hd->filename);
79
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
80
}
81
82
if (file != NULL) {
83
+ bdrv_refresh_filename(blk_bs(file));
84
filename = blk_bs(file)->filename;
85
} else {
86
/*
87
@@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
88
bdrv_unref(backing_hd);
89
}
90
91
- bdrv_refresh_filename(bs);
92
-
93
out:
94
bdrv_refresh_limits(bs, NULL);
95
}
96
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
97
g_free(child_key_dot);
98
}
99
100
- bdrv_refresh_filename(bs);
101
-
102
/* Check if any unknown options were used */
103
if (qdict_size(options) != 0) {
104
const QDictEntry *entry = qdict_first(options);
105
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
106
if (local_err != NULL) {
107
error_propagate(errp, local_err);
108
} else {
109
+ bdrv_refresh_filename(reopen_state->bs);
110
error_setg(errp, "failed while preparing to reopen image '%s'",
111
reopen_state->bs->filename);
112
}
113
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
114
/* success - we can delete the intermediate states, and link top->base */
115
/* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once
116
* we've figured out how they should work. */
117
- backing_file_str = backing_file_str ? backing_file_str : base->filename;
118
+ if (!backing_file_str) {
119
+ bdrv_refresh_filename(base);
120
+ backing_file_str = base->filename;
121
+ }
122
123
QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
124
/* Check whether we are allowed to switch c from top to base */
125
@@ -XXX,XX +XXX,XX @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs)
126
return bs->supported_zero_flags & BDRV_REQ_MAY_UNMAP;
127
}
128
129
-const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
130
-{
131
- if (bs->backing && bs->backing->bs->encrypted)
132
- return bs->backing_file;
133
- else if (bs->encrypted)
134
- return bs->filename;
135
- else
136
- return NULL;
137
-}
138
-
139
void bdrv_get_backing_filename(BlockDriverState *bs,
140
char *filename, int filename_size)
141
{
142
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
143
144
is_protocol = path_has_protocol(backing_file);
145
146
+ /* This will recursively refresh everything in the backing chain */
147
+ bdrv_refresh_filename(bs);
148
+
149
for (curr_bs = bs; curr_bs->backing; curr_bs = curr_bs->backing->bs) {
150
151
/* If either of the filename paths is actually a protocol, then
152
diff --git a/block/qapi.c b/block/qapi.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/block/qapi.c
155
+++ b/block/qapi.c
156
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
157
return NULL;
158
}
159
160
+ bdrv_refresh_filename(bs);
161
+
162
info = g_malloc0(sizeof(*info));
163
info->file = g_strdup(bs->filename);
164
info->ro = bs->read_only;
165
@@ -XXX,XX +XXX,XX @@ void bdrv_query_image_info(BlockDriverState *bs,
166
goto out;
167
}
168
169
+ bdrv_refresh_filename(bs);
170
+
171
info = g_new0(ImageInfo, 1);
172
info->filename = g_strdup(bs->filename);
173
info->format = g_strdup(bdrv_get_format_name(bs));
174
diff --git a/block/raw-format.c b/block/raw-format.c
175
index XXXXXXX..XXXXXXX 100644
176
--- a/block/raw-format.c
177
+++ b/block/raw-format.c
178
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
179
bs->file->bs->supported_zero_flags);
180
181
if (bs->probed && !bdrv_is_read_only(bs)) {
182
+ bdrv_refresh_filename(bs->file->bs);
183
fprintf(stderr,
184
"WARNING: Image format was not specified for '%s' and probing "
185
"guessed raw.\n"
186
diff --git a/block/replication.c b/block/replication.c
187
index XXXXXXX..XXXXXXX 100644
188
--- a/block/replication.c
189
+++ b/block/replication.c
190
@@ -XXX,XX +XXX,XX @@ static void replication_done(void *opaque, int ret)
191
if (ret == 0) {
192
s->stage = BLOCK_REPLICATION_DONE;
193
194
- /* refresh top bs's filename */
195
- bdrv_refresh_filename(bs);
196
s->active_disk = NULL;
197
s->secondary_disk = NULL;
198
s->hidden_disk = NULL;
199
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
200
index XXXXXXX..XXXXXXX 100644
201
--- a/block/vhdx-log.c
202
+++ b/block/vhdx-log.c
203
@@ -XXX,XX +XXX,XX @@ int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
204
205
if (logs.valid) {
206
if (bs->read_only) {
207
+ bdrv_refresh_filename(bs);
208
ret = -EPERM;
209
error_setg(errp,
210
"VHDX image file '%s' opened read-only, but "
211
diff --git a/block/vmdk.c b/block/vmdk.c
212
index XXXXXXX..XXXXXXX 100644
213
--- a/block/vmdk.c
214
+++ b/block/vmdk.c
215
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
216
extent->l1_table,
217
l1_size);
218
if (ret < 0) {
219
+ bdrv_refresh_filename(extent->file->bs);
220
error_setg_errno(errp, -ret,
221
"Could not read l1 table from extent '%s'",
222
extent->file->bs->filename);
223
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
224
extent->l1_backup_table,
225
l1_size);
226
if (ret < 0) {
227
+ bdrv_refresh_filename(extent->file->bs);
228
error_setg_errno(errp, -ret,
229
"Could not read l1 backup table from extent '%s'",
230
extent->file->bs->filename);
231
@@ -XXX,XX +XXX,XX @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
232
233
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
234
if (ret < 0) {
235
+ bdrv_refresh_filename(file->bs);
236
error_setg_errno(errp, -ret,
237
"Could not read header from file '%s'",
238
file->bs->filename);
239
@@ -XXX,XX +XXX,XX @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
240
241
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
242
if (ret < 0) {
243
+ bdrv_refresh_filename(file->bs);
244
error_setg_errno(errp, -ret,
245
"Could not read header from file '%s'",
246
file->bs->filename);
247
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
248
if (!path_is_absolute(fname) && !path_has_protocol(fname) &&
249
!desc_file_path[0])
250
{
251
+ bdrv_refresh_filename(bs->file->bs);
252
error_setg(errp, "Cannot use relative extent paths with VMDK "
253
"descriptor file '%s'", bs->file->bs->filename);
254
return -EINVAL;
255
@@ -XXX,XX +XXX,XX @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
256
{
257
ImageInfo *info = g_new0(ImageInfo, 1);
258
259
+ bdrv_refresh_filename(extent->file->bs);
260
*info = (ImageInfo){
261
.filename = g_strdup(extent->file->bs->filename),
262
.format = g_strdup(extent->type),
263
diff --git a/blockdev.c b/blockdev.c
14
diff --git a/blockdev.c b/blockdev.c
264
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
265
--- a/blockdev.c
16
--- a/blockdev.c
266
+++ b/blockdev.c
17
+++ b/blockdev.c
267
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
18
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
268
error_setg_errno(errp, -size, "bdrv_getlength failed");
19
.type = QEMU_OPT_STRING,
269
goto out;
20
.help = "chs translation (auto, lba, none)",
270
}
21
},{
271
+ bdrv_refresh_filename(state->old_bs);
22
- .name = "boot",
272
bdrv_img_create(new_image_file, format,
23
- .type = QEMU_OPT_BOOL,
273
state->old_bs->filename,
24
- .help = "(deprecated, ignored)",
274
state->old_bs->drv->format_name,
25
- },{
275
@@ -XXX,XX +XXX,XX @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
26
.name = "addr",
276
goto out;
27
.type = QEMU_OPT_STRING,
277
}
28
.help = "pci address (virtio only)",
278
assert(bdrv_get_aio_context(base_bs) == aio_context);
29
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
279
+ bdrv_refresh_filename(base_bs);
30
goto fail;
280
base_name = base_bs->filename;
281
}
31
}
282
32
283
@@ -XXX,XX +XXX,XX @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
33
- /* Deprecated option boot=[on|off] */
284
goto out;
34
- if (qemu_opt_get(legacy_opts, "boot") != NULL) {
285
}
35
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
286
} else if (has_top && top) {
36
- "ignored. Future versions will reject this parameter. Please "
287
+ /* This strcmp() is just a shortcut, there is no need to
37
- "update your scripts.\n");
288
+ * refresh @bs's filename. If it mismatches,
38
- }
289
+ * bdrv_find_backing_image() will do the refresh and may still
39
-
290
+ * return @bs. */
40
/* Other deprecated options */
291
if (strcmp(bs->filename, top) != 0) {
41
if (!qtest_enabled()) {
292
top_bs = bdrv_find_backing_image(bs, top);
42
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
293
}
43
diff --git a/qemu-doc.texi b/qemu-doc.texi
294
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
295
if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
296
assert(backup->format);
297
if (source) {
298
+ bdrv_refresh_filename(source);
299
bdrv_img_create(backup->target, backup->format, source->filename,
300
source->drv->format_name, NULL,
301
size, flags, false, &local_err);
302
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
303
break;
304
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
305
/* create new image with backing file */
306
+ bdrv_refresh_filename(source);
307
bdrv_img_create(arg->target, format,
308
source->filename,
309
source->drv->format_name,
310
diff --git a/qemu-img.c b/qemu-img.c
311
index XXXXXXX..XXXXXXX 100644
44
index XXXXXXX..XXXXXXX 100644
312
--- a/qemu-img.c
45
--- a/qemu-doc.texi
313
+++ b/qemu-img.c
46
+++ b/qemu-doc.texi
314
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
47
@@ -XXX,XX +XXX,XX @@ deprecated.
315
BlockDriverState *file;
48
316
bool has_offset;
49
@section System emulator command line arguments
317
int64_t map;
50
318
+ char *filename = NULL;
51
-@subsection -drive boot=on|off (since 1.3.0)
319
52
-
320
/* As an optimization, we could cache the current range of unallocated
53
-The ``boot=on|off'' option to the ``-drive'' argument is
321
* clusters in each file of the chain, and avoid querying the same
54
-ignored. Applications should use the ``bootindex=N'' parameter
322
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
55
-to set an absolute ordering between devices instead.
323
56
-
324
has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
57
@subsection -tdf (since 1.3.0)
325
58
326
+ if (file && has_offset) {
59
The ``-tdf'' argument is ignored. The behaviour implemented
327
+ bdrv_refresh_filename(file);
328
+ filename = file->filename;
329
+ }
330
+
331
*e = (MapEntry) {
332
.start = offset,
333
.length = bytes,
334
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
335
.offset = map,
336
.has_offset = has_offset,
337
.depth = depth,
338
- .has_filename = file && has_offset,
339
- .filename = file && has_offset ? file->filename : NULL,
340
+ .has_filename = filename,
341
+ .filename = filename,
342
};
343
344
return 0;
345
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
346
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
347
}
348
349
+ bdrv_refresh_filename(bs);
350
overlay_filename = bs->exact_filename[0] ? bs->exact_filename
351
: bs->filename;
352
out_real_path = g_malloc(PATH_MAX);
353
--
60
--
354
2.20.1
61
2.13.6
355
62
356
63
diff view generated by jsdifflib
1
From: Daniel Henrique Barboza <danielhb413@gmail.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
At this moment, QEMU attempts to create/load/delete snapshots
3
It's been marked as deprecated since QEMU v2.10.0, and so far nobody
4
by using either an ID (id_str) or a name. The problem is that the code
4
complained that we should keep it, so let's remove this legacy option
5
isn't consistent of whether the entered argument is an ID or a name,
5
now to simplify the code quite a bit.
6
causing unexpected behaviors.
6
7
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
For example, when creating snapshots via savevm <arg>, what happens is that
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
"arg" is treated as both name and id_str. In a guest without snapshots, create
9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
10
a single snapshot via savevm:
11
12
(qemu) savevm 0
13
(qemu) info snapshots
14
List of snapshots present on all disks:
15
ID TAG VM SIZE DATE VM CLOCK
16
-- 0 741M 2018-07-31 13:39:56 00:41:25.313
17
18
A snapshot with name "0" is created. ID is hidden from the user, but the
19
ID is a non-zero integer that starts at "1". Thus, this snapshot has
20
id_str=1, TAG="0". Creating a second snapshot with arg = 1, the first one
21
is deleted:
22
23
(qemu) savevm 1
24
(qemu) info snapshots
25
List of snapshots present on all disks:
26
ID TAG VM SIZE DATE VM CLOCK
27
-- 1 741M 2018-07-31 13:42:14 00:41:55.252
28
29
What happened?
30
31
- when creating the second snapshot, a verification is done inside
32
bdrv_all_delete_snapshot to delete any existing snapshots that matches an
33
string argument. Here, the code calls bdrv_all_delete_snapshot("1", ...);
34
35
- bdrv_all_delete_snapshot calls bdrv_snapshot_find(..., "1") for each
36
BlockDriverState of the guest. And this is where things goes tilting:
37
bdrv_snapshot_find does a search by both id_str and name. It finds
38
out that there is a snapshot that has id_str = 1, stores a reference
39
to the snapshot in the sn_info pointer and then returns match found;
40
41
- since a match was found, a call to bdrv_snapshot_delete_by_id_or_name() is
42
made. This function ignores the pointer written by bdrv_snapshot_find. Instead,
43
it deletes the snapshot using bdrv_snapshot_delete() calling it first with
44
id_str = 1. If it fails to delete, then it calls it again with name = 1.
45
46
- after all that, QEMU creates the new snapshot, that has id_str = 1 and
47
name = 1. The user is left wondering that happened with the first snapshot
48
created. Similar bugs can be triggered when using loadvm and delvm.
49
50
Before contemplating discarding the use of ID input in these operations,
51
I've searched the code of what would be the implications. My findings
52
are:
53
54
- the RBD and Sheepdog drivers don't care. Both uses the 'name' field as
55
key in their logic, making id_str = name when appropriate.
56
replay-snapshot.c does not make any special use of id_str;
57
58
- qcow2 uses id_str as an unique identifier but it is automatically
59
calculated, not being influenced by user input. Other than that, there are
60
no distinguish operations made only with id_str;
61
62
- in blockdev.c, the delete operation uses a match of both id_str AND
63
name. Given that id_str is either a copy of 'name' or auto-generated,
64
we're fine here.
65
66
This gives motivation to not consider ID as a valid user input in HMP
67
commands - sticking with 'name' input only is more consistent. To
68
accomplish that, the following changes were made in this patch:
69
70
- bdrv_snapshot_find() does not match for id_str anymore, only 'name'. The
71
function is called in save_snapshot(), load_snapshot(), bdrv_all_delete_snapshot()
72
and bdrv_all_find_snapshot(). This change makes the search function more
73
predictable and does not change the behavior of any underlying code that uses
74
these affected functions, which are related to HMP (which is fine) and the
75
main loop inside vl.c (which doesn't care about it anyways);
76
77
- bdrv_all_delete_snapshot() does not call bdrv_snapshot_delete_by_id_or_name
78
anymore. Instead, it uses the pointer returned by bdrv_snapshot_find to
79
erase the snapshot with the exact match of id_str an name. This function
80
is called in save_snapshot and hmp_delvm, thus this change produces the
81
intended effect;
82
83
- documentation changes to reflect the new behavior. I consider this to
84
be an API fix instead of an API change - the user was already creating
85
snapshots using 'name', but now he/she will also enjoy a consistent
86
behavior.
87
88
Ideally we would get rid of the id_str field entirely, but this would have
89
repercussions on existing snapshots. Another day perhaps.
90
91
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
92
Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
93
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
94
---
11
---
95
block/snapshot.c | 5 +++--
12
vl.c | 86 ++-------------------------------------------------------
96
hmp-commands.hx | 32 ++++++++++++++++++++------------
13
qemu-doc.texi | 8 ------
97
2 files changed, 23 insertions(+), 14 deletions(-)
14
qemu-options.hx | 19 ++-----------
98
15
3 files changed, 4 insertions(+), 109 deletions(-)
99
diff --git a/block/snapshot.c b/block/snapshot.c
16
17
diff --git a/vl.c b/vl.c
100
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
101
--- a/block/snapshot.c
19
--- a/vl.c
102
+++ b/block/snapshot.c
20
+++ b/vl.c
103
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
21
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
104
}
22
const char *boot_order = NULL;
105
for (i = 0; i < nb_sns; i++) {
23
const char *boot_once = NULL;
106
sn = &sn_tab[i];
24
DisplayState *ds;
107
- if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
25
- int cyls, heads, secs, translation;
108
+ if (!strcmp(sn->name, name)) {
26
QemuOpts *opts, *machine_opts;
109
*sn_info = *sn;
27
- QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL;
110
ret = 0;
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)
111
break;
43
break;
112
@@ -XXX,XX +XXX,XX @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs,
44
if (argv[optind][0] != '-') {
113
aio_context_acquire(ctx);
45
- hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
114
if (bdrv_can_snapshot(bs) &&
46
+ drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
115
bdrv_snapshot_find(bs, snapshot, name) >= 0) {
47
} else {
116
- ret = bdrv_snapshot_delete_by_id_or_name(bs, name, err);
48
const QEMUOption *popt;
117
+ ret = bdrv_snapshot_delete(bs, snapshot->id_str,
49
118
+ snapshot->name, err);
50
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
119
}
51
cpu_model = optarg;
120
aio_context_release(ctx);
52
break;
121
if (ret < 0) {
53
case QEMU_OPTION_hda:
122
diff --git a/hmp-commands.hx b/hmp-commands.hx
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
123
index XXXXXXX..XXXXXXX 100644
144
index XXXXXXX..XXXXXXX 100644
124
--- a/hmp-commands.hx
145
--- a/qemu-doc.texi
125
+++ b/hmp-commands.hx
146
+++ b/qemu-doc.texi
126
@@ -XXX,XX +XXX,XX @@ ETEXI
147
@@ -XXX,XX +XXX,XX @@ The ``--net dump'' argument is now replaced with the
127
{
148
``-object filter-dump'' argument which works in combination
128
.name = "savevm",
149
with the modern ``-netdev`` backends instead.
129
.args_type = "name:s?",
150
130
- .params = "[tag|id]",
151
-@subsection -hdachs (since 2.10.0)
131
- .help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created",
152
-
132
+ .params = "tag",
153
-The ``-hdachs'' argument is now a synonym for setting
133
+ .help = "save a VM snapshot. If no tag is provided, a new snapshot is created",
154
-the ``cyls'', ``heads'', ``secs'', and ``trans'' properties
134
.cmd = hmp_savevm,
155
-on the ``ide-hd'' device using the ``-device'' argument.
135
},
156
-The new syntax allows different settings to be provided
136
157
-per disk.
137
STEXI
158
-
138
-@item savevm [@var{tag}|@var{id}]
159
@subsection -usbdevice (since 2.10.0)
139
+@item savevm @var{tag}
160
140
@findex savevm
161
The ``-usbdevice DEV'' argument is now a synonym for setting
141
Create a snapshot of the whole virtual machine. If @var{tag} is
162
diff --git a/qemu-options.hx b/qemu-options.hx
142
provided, it is used as human readable identifier. If there is already
163
index XXXXXXX..XXXXXXX 100644
143
-a snapshot with the same tag or ID, it is replaced. More info at
164
--- a/qemu-options.hx
144
+a snapshot with the same tag, it is replaced. More info at
165
+++ b/qemu-options.hx
145
@ref{vm_snapshots}.
166
@@ -XXX,XX +XXX,XX @@ of available connectors of a given interface type.
146
+
167
@item media=@var{media}
147
+Since 4.0, savevm stopped allowing the snapshot id to be set, accepting
168
This option defines the type of the media: disk or cdrom.
148
+only @var{tag} as parameter.
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}).
149
ETEXI
179
ETEXI
150
180
151
{
181
-DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
152
.name = "loadvm",
182
- "-hdachs c,h,s[,t]\n" \
153
.args_type = "name:s",
183
- " force hard disk 0 physical geometry and the optional BIOS\n" \
154
- .params = "tag|id",
184
- " translation (t=none or lba) (usually QEMU can guess them)\n",
155
- .help = "restore a VM snapshot from its tag or id",
185
- QEMU_ARCH_ALL)
156
+ .params = "tag",
186
-STEXI
157
+ .help = "restore a VM snapshot from its tag",
187
-@item -hdachs @var{c},@var{h},@var{s},[,@var{t}]
158
.cmd = hmp_loadvm,
188
-@findex -hdachs
159
.command_completion = loadvm_completion,
189
-Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
160
},
190
-@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
161
191
-translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
162
STEXI
192
-all those parameters. This option is deprecated, please use
163
-@item loadvm @var{tag}|@var{id}
193
-@code{-device ide-hd,cyls=c,heads=h,secs=s,...} instead.
164
+@item loadvm @var{tag}
194
-ETEXI
165
@findex loadvm
195
-
166
Set the whole virtual machine to the snapshot identified by the tag
196
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
167
-@var{tag} or the unique snapshot ID @var{id}.
197
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
168
+@var{tag}.
198
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n"
169
+
170
+Since 4.0, loadvm stopped accepting snapshot id as parameter.
171
ETEXI
172
173
{
174
.name = "delvm",
175
.args_type = "name:s",
176
- .params = "tag|id",
177
- .help = "delete a VM snapshot from its tag or id",
178
+ .params = "tag",
179
+ .help = "delete a VM snapshot from its tag",
180
.cmd = hmp_delvm,
181
.command_completion = delvm_completion,
182
},
183
184
STEXI
185
-@item delvm @var{tag}|@var{id}
186
+@item delvm @var{tag}
187
@findex delvm
188
-Delete the snapshot identified by @var{tag} or @var{id}.
189
+Delete the snapshot identified by @var{tag}.
190
+
191
+Since 4.0, delvm stopped deleting snapshots by snapshot id, accepting
192
+only @var{tag} as parameter.
193
ETEXI
194
195
{
196
--
199
--
197
2.20.1
200
2.13.6
198
201
199
202
diff view generated by jsdifflib
Deleted patch
1
From: Daniel Henrique Barboza <danielhb413@gmail.com>
2
1
3
After the previous patch, the only instance of this function left
4
is inside qemu-img.c.
5
6
qemu-img is using it inside the 'img_snapshot' function to delete
7
snapshots in the SNAPSHOT_DELETE case, based on a "snapshot_name"
8
string that refers to the tag, not ID, of the QEMUSnapshotInfo struct.
9
This can be verified by checking the SNAPSHOT_CREATE case that
10
comes shortly before SNAPSHOT_DELETE. In that case, the same
11
"snapshot_name" variable is being strcpy to the 'name' field
12
of the QEMUSnapshotInfo struct sn:
13
14
pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
15
16
Based on that, it is unlikely that "snapshot_name" might contain
17
an "id" in SNAPSHOT_DELETE.
18
19
This patch changes SNAPSHOT_DELETE to use snapshot_find() and
20
snapshot_delete() instead of bdrv_snapshot_delete_by_id_or_name.
21
After that, there is no instances left of bdrv_snapshot_delete_by_id_or_name
22
in the code, so it is safe to remove it entirely.
23
24
Suggested-by: Murilo Opsfelder Araujo <muriloo@linux.ibm.com>
25
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
---
28
include/block/snapshot.h | 3 ---
29
block/snapshot.c | 20 --------------------
30
qemu-img.c | 15 +++++++++++----
31
3 files changed, 11 insertions(+), 27 deletions(-)
32
33
diff --git a/include/block/snapshot.h b/include/block/snapshot.h
34
index XXXXXXX..XXXXXXX 100644
35
--- a/include/block/snapshot.h
36
+++ b/include/block/snapshot.h
37
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_delete(BlockDriverState *bs,
38
const char *snapshot_id,
39
const char *name,
40
Error **errp);
41
-int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
42
- const char *id_or_name,
43
- Error **errp);
44
int bdrv_snapshot_list(BlockDriverState *bs,
45
QEMUSnapshotInfo **psn_info);
46
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
47
diff --git a/block/snapshot.c b/block/snapshot.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/snapshot.c
50
+++ b/block/snapshot.c
51
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_delete(BlockDriverState *bs,
52
return ret;
53
}
54
55
-int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
56
- const char *id_or_name,
57
- Error **errp)
58
-{
59
- int ret;
60
- Error *local_err = NULL;
61
-
62
- ret = bdrv_snapshot_delete(bs, id_or_name, NULL, &local_err);
63
- if (ret == -ENOENT || ret == -EINVAL) {
64
- error_free(local_err);
65
- local_err = NULL;
66
- ret = bdrv_snapshot_delete(bs, NULL, id_or_name, &local_err);
67
- }
68
-
69
- if (ret < 0) {
70
- error_propagate(errp, local_err);
71
- }
72
- return ret;
73
-}
74
-
75
int bdrv_snapshot_list(BlockDriverState *bs,
76
QEMUSnapshotInfo **psn_info)
77
{
78
diff --git a/qemu-img.c b/qemu-img.c
79
index XXXXXXX..XXXXXXX 100644
80
--- a/qemu-img.c
81
+++ b/qemu-img.c
82
@@ -XXX,XX +XXX,XX @@ static int img_snapshot(int argc, char **argv)
83
break;
84
85
case SNAPSHOT_DELETE:
86
- bdrv_snapshot_delete_by_id_or_name(bs, snapshot_name, &err);
87
- if (err) {
88
- error_reportf_err(err, "Could not delete snapshot '%s': ",
89
- snapshot_name);
90
+ ret = bdrv_snapshot_find(bs, &sn, snapshot_name);
91
+ if (ret < 0) {
92
+ error_report("Could not delete snapshot '%s': snapshot not "
93
+ "found", snapshot_name);
94
ret = 1;
95
+ } else {
96
+ ret = bdrv_snapshot_delete(bs, sn.id_str, sn.name, &err);
97
+ if (ret < 0) {
98
+ error_reportf_err(err, "Could not delete snapshot '%s': ",
99
+ snapshot_name);
100
+ ret = 1;
101
+ }
102
}
103
break;
104
}
105
--
106
2.20.1
107
108
diff view generated by jsdifflib
Deleted patch
1
From: Daniel Henrique Barboza <danielhb413@gmail.com>
2
1
3
In qcow2_snapshot_create there is the following code block:
4
5
/* Generate an ID */
6
find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
7
8
/* Check that the ID is unique */
9
if (find_snapshot_by_id_and_name(bs, sn_info->id_str, NULL) >= 0) {
10
return -EEXIST;
11
}
12
13
find_new_snapshot_id cycles through all snapshots, getting the id_str
14
as an unsigned long int, calculating the max id_max value of all the
15
existing id_strs and writing in the id_str pointer id_max + 1:
16
17
for(i = 0; i < s->nb_snapshots; i++) {
18
sn = s->snapshots + i;
19
id = strtoul(sn->id_str, NULL, 10);
20
if (id > id_max)
21
id_max = id;
22
}
23
snprintf(id_str, id_str_size, "%lu", id_max + 1);
24
25
Here, sn_info->id_str will have the unique value id_max + 1. Right
26
after that, find_snapshot_by_id_and_name is called with
27
id = sn_info->id_str and name = NULL. This will cause the function
28
to execute the following:
29
30
} else if (id) {
31
for (i = 0; i < s->nb_snapshots; i++) {
32
if (!strcmp(s->snapshots[i].id_str, id)) {
33
return i;
34
}
35
}
36
}
37
38
In short, we're searching the existing snapshots to see if sn_info->id_str
39
matches any existing id, right after we set in the previous line a
40
sn_info->id_str value that is already unique.
41
42
The first code block goes way back to commit 585f8587ad, a 2006 commit from
43
Fabrice Bellard that simply says "new qcow2 disk image format". No more
44
info is provided about this logic in any subsequent commits that moved
45
this code block around.
46
47
I can't say about the original design, but the current logic is redundant.
48
bdrv_snapshot_create is called in aio_context lock, forbidding any
49
concurrent call to accidentally create a new snapshot between
50
the find_new_snapshot_id and find_snapshot_by_id_and_name calls. What
51
we're ending up doing is to cycle through the snapshots two times
52
for no viable reason.
53
54
This patch eliminates the redundancy by removing the 'id is unique'
55
check that calls find_snapshot_by_id_and_name.
56
57
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
58
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
59
---
60
block/qcow2-snapshot.c | 5 -----
61
1 file changed, 5 deletions(-)
62
63
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/block/qcow2-snapshot.c
66
+++ b/block/qcow2-snapshot.c
67
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
68
/* Generate an ID */
69
find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
70
71
- /* Check that the ID is unique */
72
- if (find_snapshot_by_id_and_name(bs, sn_info->id_str, NULL) >= 0) {
73
- return -EEXIST;
74
- }
75
-
76
/* Populate sn with passed data */
77
sn->id_str = g_strdup(sn_info->id_str);
78
sn->name = g_strdup(sn_info->name);
79
--
80
2.20.1
81
82
diff view generated by jsdifflib
Deleted patch
1
From: Denis Plotnikov <dplotnikov@virtuozzo.com>
2
1
3
Adds a fast path on aio context setting preventing
4
unnecessary context setting routine.
5
Also, it prevents issues with cyclic walk of child
6
bds-es appeared because of registering aio walking
7
notifiers:
8
9
Call stack:
10
11
0 __GI_raise
12
1 __GI_abort
13
2 __assert_fail_base
14
3 __GI___assert_fail
15
4 bdrv_detach_aio_context (bs=0x55f54d65c000) <<<
16
5 bdrv_detach_aio_context (bs=0x55f54fc8a800)
17
6 bdrv_set_aio_context (bs=0x55f54fc8a800, ...)
18
7 block_job_attached_aio_context
19
8 bdrv_attach_aio_context (bs=0x55f54d65c000, ...) <<<
20
9 bdrv_set_aio_context (bs=0x55f54d65c000)
21
10 blk_set_aio_context
22
11 virtio_blk_data_plane_stop
23
12 virtio_bus_stop_ioeventfd
24
13 virtio_vmstate_change
25
14 vm_state_notify (running=0, state=RUN_STATE_SHUTDOWN)
26
15 do_vm_stop (state=RUN_STATE_SHUTDOWN, send_stop=true)
27
16 vm_stop (state=RUN_STATE_SHUTDOWN)
28
17 main_loop_should_exit
29
18 main_loop
30
19 main
31
32
This can happen because of "new" context attachment to VM disk bds.
33
When attaching a new context the corresponding aio context handler is
34
called for each of aio_notifiers registered on the VM disk bds context.
35
Among those handlers, there is the block_job_attached_aio_context handler
36
which sets a new aio context for the block job bds. When doing so,
37
the old context is detached from all the block job bds children and one of
38
them is the VM disk bds, serving as backing store for the blockjob bds,
39
although the VM disk bds is actually the initializer of that process.
40
Since the VM disk bds is protected with walking_aio_notifiers flag
41
from double processing in recursive calls, the assert fires.
42
43
Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
44
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
45
---
46
block.c | 4 ++++
47
1 file changed, 4 insertions(+)
48
49
diff --git a/block.c b/block.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/block.c
52
+++ b/block.c
53
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
54
{
55
AioContext *ctx = bdrv_get_aio_context(bs);
56
57
+ if (ctx == new_context) {
58
+ return;
59
+ }
60
+
61
aio_disable_external(ctx);
62
bdrv_parent_drained_begin(bs, NULL, false);
63
bdrv_drain(bs); /* ensure there are no in-flight requests */
64
--
65
2.20.1
66
67
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
The QEMU_PACKED is causing a compiler warning/error with GCC 9:
3
Looks like we forgot to announce the deprecation of these options in
4
the corresponding chapter of the qemu-doc text, so let's do that now.
4
5
5
CC block/nvme.o
6
block/nvme.c: In function ‘nvme_create_queue_pair’:
7
block/nvme.c:209:22: error: taking address of packed member of
8
‘struct <anonymous>’ may result in an unaligned pointer value
9
[-Werror=address-of-packed-member]
10
209 | q->sq.doorbell = &s->regs->doorbells[idx * 2 * s->doorbell_scale];
11
12
All members of the struct are naturally aligned, so there should
13
not be the need for QEMU_PACKED here, and the following QEMU_BUILD_BUG_ON
14
also ensures that there is no padding. Thus simply remove the QEMU_PACKED
15
here.
16
17
Buglink: https://bugs.launchpad.net/qemu/+bug/1817525
18
Reported-by: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
19
Signed-off-by: Thomas Huth <thuth@redhat.com>
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Markus Armbruster <armbru@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
10
---
23
block/nvme.c | 2 +-
11
qemu-doc.texi | 15 +++++++++++++++
24
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 15 insertions(+)
25
13
26
diff --git a/block/nvme.c b/block/nvme.c
14
diff --git a/qemu-doc.texi b/qemu-doc.texi
27
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
28
--- a/block/nvme.c
16
--- a/qemu-doc.texi
29
+++ b/block/nvme.c
17
+++ b/qemu-doc.texi
30
@@ -XXX,XX +XXX,XX @@ typedef volatile struct {
18
@@ -XXX,XX +XXX,XX @@ longer be directly supported in QEMU.
31
uint8_t reserved1[0xec0];
19
The ``-drive if=scsi'' argument is replaced by the the
32
uint8_t cmd_set_specfic[0x100];
20
``-device BUS-TYPE'' argument combined with ``-drive if=none''.
33
uint32_t doorbells[];
21
34
-} QEMU_PACKED NVMeRegs;
22
+@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
35
+} NVMeRegs;
23
+
36
24
+The drive geometry arguments are replaced by the the geometry arguments
37
QEMU_BUILD_BUG_ON(offsetof(NVMeRegs, doorbells) != 0x1000);
25
+that can be specified with the ``-device'' parameter.
38
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
39
--
40
--
40
2.20.1
41
2.13.6
41
42
42
43
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
Currently, BlockDriver.bdrv_refresh_filename() is supposed to both
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
refresh the filename (BDS.exact_filename) and set BDS.full_open_options.
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Now that we have generic code in the central bdrv_refresh_filename() for
6
creating BDS.full_open_options, we can drop the latter part from all
7
BlockDriver.bdrv_refresh_filename() implementations.
8
9
This also means that we can drop all of the existing default code for
10
this from the global bdrv_refresh_filename() itself.
11
12
Furthermore, we now have to call BlockDriver.bdrv_refresh_filename()
13
after having set BDS.full_open_options, because the block driver's
14
implementation should now be allowed to depend on BDS.full_open_options
15
being set correctly.
16
17
Finally, with this patch we can drop the @options parameter from
18
BlockDriver.bdrv_refresh_filename(); also, add a comment on this
19
function's purpose in block/block_int.h while touching its interface.
20
21
This completely obsoletes blklogwrite's implementation of
22
.bdrv_refresh_filename().
23
24
Signed-off-by: Max Reitz <mreitz@redhat.com>
25
Message-id: 20190201192935.18394-25-mreitz@redhat.com
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
---
5
---
28
include/block/block_int.h | 6 +-
6
include/block/block_int.h | 1 -
29
block.c | 131 +++++++------------------------------
7
block/io.c | 18 ------------------
30
block/blkdebug.c | 54 ++++++---------
8
2 files changed, 19 deletions(-)
31
block/blklogwrites.c | 22 -------
32
block/blkverify.c | 16 +----
33
block/commit.c | 2 +-
34
block/mirror.c | 2 +-
35
block/nbd.c | 23 +------
36
block/nfs.c | 36 +---------
37
block/null.c | 22 ++++---
38
block/nvme.c | 22 ++++---
39
block/quorum.c | 30 ---------
40
tests/qemu-iotests/228 | 4 --
41
tests/qemu-iotests/228.out | 2 +-
42
14 files changed, 81 insertions(+), 291 deletions(-)
43
9
44
diff --git a/include/block/block_int.h b/include/block/block_int.h
10
diff --git a/include/block/block_int.h b/include/block/block_int.h
45
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/block_int.h
12
--- a/include/block/block_int.h
47
+++ b/include/block/block_int.h
13
+++ b/include/block/block_int.h
48
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
14
@@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk);
49
Error **errp);
15
bool blk_dev_is_medium_locked(BlockBackend *blk);
50
int (*bdrv_make_empty)(BlockDriverState *bs);
16
51
17
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
52
- void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
18
-bool bdrv_requests_pending(BlockDriverState *bs);
53
+ /*
19
54
+ * Refreshes the bs->exact_filename field. If that is impossible,
20
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
55
+ * bs->exact_filename has to be left empty.
21
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
56
+ */
22
diff --git a/block/io.c b/block/io.c
57
+ void (*bdrv_refresh_filename)(BlockDriverState *bs);
58
59
/*
60
* Gathers the open options for all children into @target.
61
diff --git a/block.c b/block.c
62
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
63
--- a/block.c
24
--- a/block/io.c
64
+++ b/block.c
25
+++ b/block/io.c
65
@@ -XXX,XX +XXX,XX @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
26
@@ -XXX,XX +XXX,XX @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
66
return found_any;
27
assert(old >= 1);
67
}
28
}
68
29
69
-static bool append_open_options(QDict *d, BlockDriverState *bs)
30
-/* Check if any requests are in-flight (including throttled requests) */
31
-bool bdrv_requests_pending(BlockDriverState *bs)
70
-{
32
-{
71
- const QDictEntry *entry;
33
- BdrvChild *child;
72
- QemuOptDesc *desc;
73
- bool found_any = false;
74
-
34
-
75
- for (entry = qdict_first(bs->options); entry;
35
- if (atomic_read(&bs->in_flight)) {
76
- entry = qdict_next(bs->options, entry))
36
- return true;
77
- {
78
- /* Exclude all non-driver-specific options */
79
- for (desc = bdrv_runtime_opts.desc; desc->name; desc++) {
80
- if (!strcmp(qdict_entry_key(entry), desc->name)) {
81
- break;
82
- }
83
- }
84
- if (desc->name) {
85
- continue;
86
- }
87
-
88
- qdict_put_obj(d, qdict_entry_key(entry),
89
- qobject_ref(qdict_entry_value(entry)));
90
- found_any = true;
91
- }
37
- }
92
-
38
-
93
- return found_any;
39
- QLIST_FOREACH(child, &bs->children, next) {
94
-}
40
- if (bdrv_requests_pending(child->bs)) {
95
-
41
- return true;
96
/* Note: This function may return false positives; it may return true
97
* even if opening the backing file specified by bs's image header
98
* would result in exactly bs->backing. */
99
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
100
BdrvChild *child;
101
QDict *opts;
102
bool backing_overridden;
103
+ bool generate_json_filename; /* Whether our default implementation should
104
+ fill exact_filename (false) or not (true) */
105
106
if (!drv) {
107
return;
108
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
109
backing_overridden = false;
110
}
111
112
- if (drv->bdrv_refresh_filename) {
113
- /* Obsolete information is of no use here, so drop the old file name
114
- * information before refreshing it */
115
- bs->exact_filename[0] = '\0';
116
- if (bs->full_open_options) {
117
- qobject_unref(bs->full_open_options);
118
- bs->full_open_options = NULL;
119
- }
120
-
121
- opts = qdict_new();
122
- append_open_options(opts, bs);
123
- drv->bdrv_refresh_filename(bs, opts);
124
- qobject_unref(opts);
125
- } else if (bs->file) {
126
- /* Try to reconstruct valid information from the underlying file */
127
- bool has_open_options;
128
-
129
- bs->exact_filename[0] = '\0';
130
- if (bs->full_open_options) {
131
- qobject_unref(bs->full_open_options);
132
- bs->full_open_options = NULL;
133
- }
134
-
135
- opts = qdict_new();
136
- has_open_options = append_open_options(opts, bs);
137
- has_open_options |= backing_overridden;
138
-
139
- /* If no specific options have been given for this BDS, the filename of
140
- * the underlying file should suffice for this one as well */
141
- if (bs->file->bs->exact_filename[0] && !has_open_options) {
142
- strcpy(bs->exact_filename, bs->file->bs->exact_filename);
143
- }
144
- /* Reconstructing the full options QDict is simple for most format block
145
- * drivers, as long as the full options are known for the underlying
146
- * file BDS. The full options QDict of that file BDS should somehow
147
- * contain a representation of the filename, therefore the following
148
- * suffices without querying the (exact_)filename of this BDS. */
149
- if (bs->file->bs->full_open_options &&
150
- (!bs->backing || bs->backing->bs->full_open_options))
151
- {
152
- qdict_put_str(opts, "driver", drv->format_name);
153
- qdict_put(opts, "file",
154
- qobject_ref(bs->file->bs->full_open_options));
155
-
156
- if (bs->backing) {
157
- qdict_put(opts, "backing",
158
- qobject_ref(bs->backing->bs->full_open_options));
159
- } else if (backing_overridden) {
160
- qdict_put_null(opts, "backing");
161
- }
162
-
163
- bs->full_open_options = opts;
164
- } else {
165
- qobject_unref(opts);
166
- }
167
- } else if (!bs->full_open_options && qdict_size(bs->options)) {
168
- /* There is no underlying file BDS (at least referenced by BDS.file),
169
- * so the full options QDict should be equal to the options given
170
- * specifically for this block device when it was opened (plus the
171
- * driver specification).
172
- * Because those options don't change, there is no need to update
173
- * full_open_options when it's already set. */
174
-
175
- opts = qdict_new();
176
- append_open_options(opts, bs);
177
- qdict_put_str(opts, "driver", drv->format_name);
178
-
179
- if (bs->exact_filename[0]) {
180
- /* This may not work for all block protocol drivers (some may
181
- * require this filename to be parsed), but we have to find some
182
- * default solution here, so just include it. If some block driver
183
- * does not support pure options without any filename at all or
184
- * needs some special format of the options QDict, it needs to
185
- * implement the driver-specific bdrv_refresh_filename() function.
186
- */
187
- qdict_put_str(opts, "filename", bs->exact_filename);
188
- }
189
-
190
- bs->full_open_options = opts;
191
- }
192
-
193
/* Gather the options QDict */
194
opts = qdict_new();
195
- append_strong_runtime_options(opts, bs);
196
+ generate_json_filename = append_strong_runtime_options(opts, bs);
197
+ generate_json_filename |= backing_overridden;
198
199
if (drv->bdrv_gather_child_options) {
200
/* Some block drivers may not want to present all of their children's
201
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
202
qobject_unref(bs->full_open_options);
203
bs->full_open_options = opts;
204
205
+ if (drv->bdrv_refresh_filename) {
206
+ /* Obsolete information is of no use here, so drop the old file name
207
+ * information before refreshing it */
208
+ bs->exact_filename[0] = '\0';
209
+
210
+ drv->bdrv_refresh_filename(bs);
211
+ } else if (bs->file) {
212
+ /* Try to reconstruct valid information from the underlying file */
213
+
214
+ bs->exact_filename[0] = '\0';
215
+
216
+ /* If no specific options have been given for this BDS, the filename of
217
+ * the underlying file should suffice for this one as well */
218
+ if (bs->file->bs->exact_filename[0] && !generate_json_filename) {
219
+ strcpy(bs->exact_filename, bs->file->bs->exact_filename);
220
+ }
221
+ }
222
+
223
if (bs->exact_filename[0]) {
224
pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename);
225
} else {
226
diff --git a/block/blkdebug.c b/block/blkdebug.c
227
index XXXXXXX..XXXXXXX 100644
228
--- a/block/blkdebug.c
229
+++ b/block/blkdebug.c
230
@@ -XXX,XX +XXX,XX @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
231
return bdrv_getlength(bs->file->bs);
232
}
233
234
-static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
235
+static void blkdebug_refresh_filename(BlockDriverState *bs)
236
{
237
BDRVBlkdebugState *s = bs->opaque;
238
- QDict *opts;
239
const QDictEntry *e;
240
- bool force_json = false;
241
-
242
- for (e = qdict_first(options); e; e = qdict_next(options, e)) {
243
- if (strcmp(qdict_entry_key(e), "config") &&
244
- strcmp(qdict_entry_key(e), "x-image"))
245
- {
246
- force_json = true;
247
- break;
248
- }
249
- }
250
+ int ret;
251
252
- if (force_json && !bs->file->bs->full_open_options) {
253
- /* The config file cannot be recreated, so creating a plain filename
254
- * is impossible */
255
+ if (!bs->file->bs->exact_filename[0]) {
256
return;
257
}
258
259
- if (!force_json && bs->file->bs->exact_filename[0]) {
260
- int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
261
- "blkdebug:%s:%s", s->config_file ?: "",
262
- bs->file->bs->exact_filename);
263
- if (ret >= sizeof(bs->exact_filename)) {
264
- /* An overflow makes the filename unusable, so do not report any */
265
- bs->exact_filename[0] = 0;
266
+ for (e = qdict_first(bs->full_open_options); e;
267
+ e = qdict_next(bs->full_open_options, e))
268
+ {
269
+ /* Real child options are under "image", but "x-image" may
270
+ * contain a filename */
271
+ if (strcmp(qdict_entry_key(e), "config") &&
272
+ strcmp(qdict_entry_key(e), "image") &&
273
+ strcmp(qdict_entry_key(e), "x-image") &&
274
+ strcmp(qdict_entry_key(e), "driver"))
275
+ {
276
+ return;
277
}
278
}
279
280
- opts = qdict_new();
281
- qdict_put_str(opts, "driver", "blkdebug");
282
-
283
- qdict_put(opts, "image", qobject_ref(bs->file->bs->full_open_options));
284
-
285
- for (e = qdict_first(options); e; e = qdict_next(options, e)) {
286
- if (strcmp(qdict_entry_key(e), "x-image")) {
287
- qdict_put_obj(opts, qdict_entry_key(e),
288
- qobject_ref(qdict_entry_value(e)));
289
- }
290
+ ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
291
+ "blkdebug:%s:%s",
292
+ s->config_file ?: "", bs->file->bs->exact_filename);
293
+ if (ret >= sizeof(bs->exact_filename)) {
294
+ /* An overflow makes the filename unusable, so do not report any */
295
+ bs->exact_filename[0] = 0;
296
}
297
-
298
- bs->full_open_options = opts;
299
}
300
301
static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp)
302
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
303
index XXXXXXX..XXXXXXX 100644
304
--- a/block/blklogwrites.c
305
+++ b/block/blklogwrites.c
306
@@ -XXX,XX +XXX,XX @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs)
307
return bdrv_getlength(bs->file->bs);
308
}
309
310
-static void blk_log_writes_refresh_filename(BlockDriverState *bs,
311
- QDict *options)
312
-{
313
- BDRVBlkLogWritesState *s = bs->opaque;
314
-
315
- if (bs->file->bs->full_open_options
316
- && s->log_file->bs->full_open_options)
317
- {
318
- QDict *opts = qdict_new();
319
- qdict_put_str(opts, "driver", "blklogwrites");
320
-
321
- qobject_ref(bs->file->bs->full_open_options);
322
- qdict_put(opts, "file", bs->file->bs->full_open_options);
323
- qobject_ref(s->log_file->bs->full_open_options);
324
- qdict_put(opts, "log", s->log_file->bs->full_open_options);
325
- qdict_put_int(opts, "log-sector-size", s->sectorsize);
326
-
327
- bs->full_open_options = opts;
328
- }
329
-}
330
-
331
static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
332
const BdrvChildRole *role,
333
BlockReopenQueue *ro_q,
334
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blk_log_writes = {
335
.bdrv_open = blk_log_writes_open,
336
.bdrv_close = blk_log_writes_close,
337
.bdrv_getlength = blk_log_writes_getlength,
338
- .bdrv_refresh_filename = blk_log_writes_refresh_filename,
339
.bdrv_child_perm = blk_log_writes_child_perm,
340
.bdrv_refresh_limits = blk_log_writes_refresh_limits,
341
342
diff --git a/block/blkverify.c b/block/blkverify.c
343
index XXXXXXX..XXXXXXX 100644
344
--- a/block/blkverify.c
345
+++ b/block/blkverify.c
346
@@ -XXX,XX +XXX,XX @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
347
return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate);
348
}
349
350
-static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
351
+static void blkverify_refresh_filename(BlockDriverState *bs)
352
{
353
BDRVBlkverifyState *s = bs->opaque;
354
355
- if (bs->file->bs->full_open_options
356
- && s->test_file->bs->full_open_options)
357
- {
358
- QDict *opts = qdict_new();
359
- qdict_put_str(opts, "driver", "blkverify");
360
-
361
- qdict_put(opts, "raw",
362
- qobject_ref(bs->file->bs->full_open_options));
363
- qdict_put(opts, "test",
364
- qobject_ref(s->test_file->bs->full_open_options));
365
-
366
- bs->full_open_options = opts;
367
- }
368
-
369
if (bs->file->bs->exact_filename[0]
370
&& s->test_file->bs->exact_filename[0])
371
{
372
diff --git a/block/commit.c b/block/commit.c
373
index XXXXXXX..XXXXXXX 100644
374
--- a/block/commit.c
375
+++ b/block/commit.c
376
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
377
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
378
}
379
380
-static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *opts)
381
+static void bdrv_commit_top_refresh_filename(BlockDriverState *bs)
382
{
383
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
384
bs->backing->bs->filename);
385
diff --git a/block/mirror.c b/block/mirror.c
386
index XXXXXXX..XXXXXXX 100644
387
--- a/block/mirror.c
388
+++ b/block/mirror.c
389
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
390
NULL, 0);
391
}
392
393
-static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
394
+static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs)
395
{
396
if (bs->backing == NULL) {
397
/* we can be here after failed bdrv_attach_child in
398
diff --git a/block/nbd.c b/block/nbd.c
399
index XXXXXXX..XXXXXXX 100644
400
--- a/block/nbd.c
401
+++ b/block/nbd.c
402
@@ -XXX,XX +XXX,XX @@ static void nbd_attach_aio_context(BlockDriverState *bs,
403
nbd_client_attach_aio_context(bs, new_context);
404
}
405
406
-static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
407
+static void nbd_refresh_filename(BlockDriverState *bs)
408
{
409
BDRVNBDState *s = bs->opaque;
410
- QDict *opts = qdict_new();
411
- QObject *saddr_qdict;
412
- Visitor *ov;
413
const char *host = NULL, *port = NULL, *path = NULL;
414
415
if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) {
416
@@ -XXX,XX +XXX,XX @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
417
path = s->saddr->u.q_unix.path;
418
} /* else can't represent as pseudo-filename */
419
420
- qdict_put_str(opts, "driver", "nbd");
421
-
422
if (path && s->export) {
423
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
424
"nbd+unix:///%s?socket=%s", s->export, path);
425
@@ -XXX,XX +XXX,XX @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
426
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
427
"nbd://%s:%s", host, port);
428
}
429
-
430
- ov = qobject_output_visitor_new(&saddr_qdict);
431
- visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort);
432
- visit_complete(ov, &saddr_qdict);
433
- visit_free(ov);
434
- qdict_put_obj(opts, "server", saddr_qdict);
435
-
436
- if (s->export) {
437
- qdict_put_str(opts, "export", s->export);
438
- }
439
- if (s->tlscredsid) {
440
- qdict_put_str(opts, "tls-creds", s->tlscredsid);
441
- }
442
-
443
- qdict_flatten(opts);
444
- bs->full_open_options = opts;
445
}
446
447
static char *nbd_dirname(BlockDriverState *bs, Error **errp)
448
diff --git a/block/nfs.c b/block/nfs.c
449
index XXXXXXX..XXXXXXX 100644
450
--- a/block/nfs.c
451
+++ b/block/nfs.c
452
@@ -XXX,XX +XXX,XX @@ static int nfs_reopen_prepare(BDRVReopenState *state,
453
return 0;
454
}
455
456
-static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
457
+static void nfs_refresh_filename(BlockDriverState *bs)
458
{
459
NFSClient *client = bs->opaque;
460
- QDict *opts = qdict_new();
461
- QObject *server_qdict;
462
- Visitor *ov;
463
-
464
- qdict_put_str(opts, "driver", "nfs");
465
466
if (client->uid && !client->gid) {
467
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
468
@@ -XXX,XX +XXX,XX @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
469
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
470
"nfs://%s%s", client->server->host, client->path);
471
}
472
-
473
- ov = qobject_output_visitor_new(&server_qdict);
474
- visit_type_NFSServer(ov, NULL, &client->server, &error_abort);
475
- visit_complete(ov, &server_qdict);
476
- qdict_put_obj(opts, "server", server_qdict);
477
- qdict_put_str(opts, "path", client->path);
478
-
479
- if (client->uid) {
480
- qdict_put_int(opts, "user", client->uid);
481
- }
482
- if (client->gid) {
483
- qdict_put_int(opts, "group", client->gid);
484
- }
485
- if (client->tcp_syncnt) {
486
- qdict_put_int(opts, "tcp-syn-cnt", client->tcp_syncnt);
487
- }
488
- if (client->readahead) {
489
- qdict_put_int(opts, "readahead-size", client->readahead);
490
- }
491
- if (client->pagecache) {
492
- qdict_put_int(opts, "page-cache-size", client->pagecache);
493
- }
494
- if (client->debug) {
495
- qdict_put_int(opts, "debug", client->debug);
496
- }
497
-
498
- visit_free(ov);
499
- qdict_flatten(opts);
500
- bs->full_open_options = opts;
501
}
502
503
static char *nfs_dirname(BlockDriverState *bs, Error **errp)
504
diff --git a/block/null.c b/block/null.c
505
index XXXXXXX..XXXXXXX 100644
506
--- a/block/null.c
507
+++ b/block/null.c
508
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn null_co_block_status(BlockDriverState *bs,
509
return ret;
510
}
511
512
-static void null_refresh_filename(BlockDriverState *bs, QDict *opts)
513
+static void null_refresh_filename(BlockDriverState *bs)
514
{
515
- qdict_del(opts, "filename");
516
-
517
- if (!qdict_size(opts)) {
518
- snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
519
- bs->drv->format_name);
520
+ const QDictEntry *e;
521
+
522
+ for (e = qdict_first(bs->full_open_options); e;
523
+ e = qdict_next(bs->full_open_options, e))
524
+ {
525
+ /* These options can be ignored */
526
+ if (strcmp(qdict_entry_key(e), "filename") &&
527
+ strcmp(qdict_entry_key(e), "driver"))
528
+ {
529
+ return;
530
+ }
531
}
532
533
- qdict_put_str(opts, "driver", bs->drv->format_name);
534
- bs->full_open_options = qobject_ref(opts);
535
+ snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
536
+ bs->drv->format_name);
537
}
538
539
static const char *const null_strong_runtime_opts[] = {
540
diff --git a/block/nvme.c b/block/nvme.c
541
index XXXXXXX..XXXXXXX 100644
542
--- a/block/nvme.c
543
+++ b/block/nvme.c
544
@@ -XXX,XX +XXX,XX @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state,
545
return 0;
546
}
547
548
-static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts)
549
+static void nvme_refresh_filename(BlockDriverState *bs)
550
{
551
- qdict_del(opts, "filename");
552
-
553
- if (!qdict_size(opts)) {
554
- snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
555
- bs->drv->format_name);
556
+ const QDictEntry *e;
557
+
558
+ for (e = qdict_first(bs->full_open_options); e;
559
+ e = qdict_next(bs->full_open_options, e))
560
+ {
561
+ /* These options can be ignored */
562
+ if (strcmp(qdict_entry_key(e), "filename") &&
563
+ strcmp(qdict_entry_key(e), "driver"))
564
+ {
565
+ return;
566
+ }
567
}
568
569
- qdict_put_str(opts, "driver", bs->drv->format_name);
570
- bs->full_open_options = qobject_ref(opts);
571
+ snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
572
+ bs->drv->format_name);
573
}
574
575
static void nvme_refresh_limits(BlockDriverState *bs, Error **errp)
576
diff --git a/block/quorum.c b/block/quorum.c
577
index XXXXXXX..XXXXXXX 100644
578
--- a/block/quorum.c
579
+++ b/block/quorum.c
580
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
581
bdrv_drained_end(bs);
582
}
583
584
-static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
585
-{
586
- BDRVQuorumState *s = bs->opaque;
587
- QDict *opts;
588
- QList *children;
589
- int i;
590
-
591
- for (i = 0; i < s->num_children; i++) {
592
- if (!s->children[i]->bs->full_open_options) {
593
- return;
594
- }
42
- }
595
- }
43
- }
596
-
44
-
597
- children = qlist_new();
45
- return false;
598
- for (i = 0; i < s->num_children; i++) {
599
- qlist_append(children,
600
- qobject_ref(s->children[i]->bs->full_open_options));
601
- }
602
-
603
- opts = qdict_new();
604
- qdict_put_str(opts, "driver", "quorum");
605
- qdict_put_int(opts, QUORUM_OPT_VOTE_THRESHOLD, s->threshold);
606
- qdict_put_bool(opts, QUORUM_OPT_BLKVERIFY, s->is_blkverify);
607
- qdict_put_bool(opts, QUORUM_OPT_REWRITE, s->rewrite_corrupted);
608
- qdict_put(opts, "children", children);
609
-
610
- bs->full_open_options = opts;
611
-}
46
-}
612
-
47
-
613
static void quorum_gather_child_options(BlockDriverState *bs, QDict *target,
48
typedef struct {
614
bool backing_overridden)
49
Coroutine *co;
615
{
50
BlockDriverState *bs;
616
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_quorum = {
617
618
.bdrv_open = quorum_open,
619
.bdrv_close = quorum_close,
620
- .bdrv_refresh_filename = quorum_refresh_filename,
621
.bdrv_gather_child_options = quorum_gather_child_options,
622
.bdrv_dirname = quorum_dirname,
623
624
diff --git a/tests/qemu-iotests/228 b/tests/qemu-iotests/228
625
index XXXXXXX..XXXXXXX 100755
626
--- a/tests/qemu-iotests/228
627
+++ b/tests/qemu-iotests/228
628
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \
629
overlay='node0')
630
631
# This should give us the original plain result
632
- # FIXME: Currently, it yields a json:{} filename even though it
633
- # only contains a @driver and a @file entry, so a plain
634
- # filename would obviously suffice. This is fixed by a
635
- # future patch.
636
637
log_node_info(vm.node_info('node0'))
638
639
diff --git a/tests/qemu-iotests/228.out b/tests/qemu-iotests/228.out
640
index XXXXXXX..XXXXXXX 100644
641
--- a/tests/qemu-iotests/228.out
642
+++ b/tests/qemu-iotests/228.out
643
@@ -XXX,XX +XXX,XX @@ bs->backing: (none)
644
{"execute": "blockdev-snapshot", "arguments": {"node": "original-backing", "overlay": "node0"}}
645
{"return": {}}
646
647
-bs->filename: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
648
+bs->filename: TEST_DIR/PID-top.img
649
bs->backing_file: TEST_DIR/PID-base.img
650
bs->backing->bs->filename: TEST_DIR/PID-base.img
651
652
--
51
--
653
2.20.1
52
2.13.6
654
53
655
54
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
2
Reviewed-by: Fam Zheng <famz@redhat.com>
3
On Python 2.x, strings are not always unicode strings. This function
4
checks whether a given value is a plain string, or a unicode string (if
5
there is a difference).
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Message-id: 20190210145736.1486-7-mreitz@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
3
---
12
tests/qemu-iotests/iotests.py | 6 ++++++
4
block/io.c | 6 ++++++
13
1 file changed, 6 insertions(+)
5
1 file changed, 6 insertions(+)
14
6
15
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
7
diff --git a/block/io.c b/block/io.c
16
index XXXXXXX..XXXXXXX 100644
8
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/iotests.py
9
--- a/block/io.c
18
+++ b/tests/qemu-iotests/iotests.py
10
+++ b/block/io.c
19
@@ -XXX,XX +XXX,XX @@ def image_size(img):
11
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
20
r = qemu_img_pipe('info', '--output=json', '-f', imgfmt, img)
12
BdrvNextIterator it;
21
return json.loads(r)['virtual-size']
13
GSList *aio_ctxs = NULL, *ctx;
22
14
23
+def is_str(val):
15
+ /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread
24
+ if sys.version_info.major >= 3:
16
+ * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on
25
+ return isinstance(val, str)
17
+ * nodes in several different AioContexts, so make sure we're in the main
26
+ else:
18
+ * context. */
27
+ return isinstance(val, str) or isinstance(val, unicode)
19
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
28
+
20
+
29
test_dir_re = re.compile(r"%s" % test_dir)
21
block_job_pause_all();
30
def filter_test_dir(msg):
22
31
return test_dir_re.sub("TEST_DIR", msg)
23
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
32
--
24
--
33
2.20.1
25
2.13.6
34
26
35
27
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
bdrv_drained_begin() doesn't increase bs->quiesce_counter recursively
2
and also doesn't notify other parent nodes of children, which both means
3
that the child nodes are not actually drained, and bdrv_drained_begin()
4
is providing useful functionality only on a single node.
2
5
3
Make bdrv_get_full_backing_filename() return an allocated string instead
6
To keep things consistent, we also shouldn't call the block driver
4
of placing the result in a caller-provided buffer.
7
callbacks recursively.
5
8
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
A proper recursive drain version that provides an actually working
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
drained section for child nodes will be introduced later.
8
Message-id: 20190201192935.18394-12-mreitz@redhat.com
11
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
10
---
14
---
11
include/block/block.h | 3 +--
15
block/io.c | 16 +++++++++-------
12
block.c | 48 +++++++++++++++----------------------------
16
1 file changed, 9 insertions(+), 7 deletions(-)
13
block/qapi.c | 12 ++---------
14
3 files changed, 20 insertions(+), 43 deletions(-)
15
17
16
diff --git a/include/block/block.h b/include/block/block.h
18
diff --git a/block/io.c b/block/io.c
17
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/block.h
20
--- a/block/io.c
19
+++ b/include/block/block.h
21
+++ b/block/io.c
20
@@ -XXX,XX +XXX,XX @@ void bdrv_round_to_clusters(BlockDriverState *bs,
22
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
21
23
}
22
void bdrv_get_backing_filename(BlockDriverState *bs,
24
23
char *filename, int filename_size);
25
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
24
-void bdrv_get_full_backing_filename(BlockDriverState *bs,
26
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
25
- char *dest, size_t sz, Error **errp);
27
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive)
26
+char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp);
28
{
27
char *bdrv_get_full_backing_filename_from_filename(const char *backed,
29
BdrvChild *child, *tmp;
28
const char *backing,
30
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
29
Error **errp);
31
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
30
diff --git a/block.c b/block.c
32
bdrv_coroutine_enter(bs, data.co);
31
index XXXXXXX..XXXXXXX 100644
33
BDRV_POLL_WHILE(bs, !data.done);
32
--- a/block.c
34
33
+++ b/block.c
35
- QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
34
@@ -XXX,XX +XXX,XX @@ char *bdrv_get_full_backing_filename_from_filename(const char *backed,
36
- bdrv_drain_invoke(child->bs, begin);
37
+ if (recursive) {
38
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
39
+ bdrv_drain_invoke(child->bs, begin, true);
40
+ }
35
}
41
}
36
}
42
}
37
43
38
-void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
44
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
39
- Error **errp)
45
bdrv_parent_drained_begin(bs);
40
+char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp)
46
}
41
{
47
42
char *backed;
48
- bdrv_drain_invoke(bs, true);
43
- char *full_name;
49
+ bdrv_drain_invoke(bs, true, false);
44
- Error *local_error = NULL;
50
bdrv_drain_recurse(bs);
45
46
bdrv_refresh_filename(bs);
47
48
backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
49
-
50
- full_name = bdrv_get_full_backing_filename_from_filename(backed,
51
- bs->backing_file,
52
- &local_error);
53
- if (full_name) {
54
- pstrcpy(dest, sz, full_name);
55
- g_free(full_name);
56
- } else if (local_error) {
57
- error_propagate(errp, local_error);
58
- } else if (sz > 0) {
59
- *dest = '\0';
60
- }
61
+ return bdrv_get_full_backing_filename_from_filename(backed,
62
+ bs->backing_file,
63
+ errp);
64
}
51
}
65
52
66
void bdrv_register(BlockDriver *bdrv)
53
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
67
@@ -XXX,XX +XXX,XX @@ out:
68
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
69
const char *bdref_key, Error **errp)
70
{
71
- char *backing_filename = g_malloc0(PATH_MAX);
72
+ char *backing_filename = NULL;
73
char *bdref_key_dot;
74
const char *reference = NULL;
75
int ret = 0;
76
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
77
*/
78
reference = qdict_get_try_str(parent_options, bdref_key);
79
if (reference || qdict_haskey(options, "file.filename")) {
80
- backing_filename[0] = '\0';
81
+ /* keep backing_filename NULL */
82
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
83
qobject_unref(options);
84
goto free_exit;
85
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
86
implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file);
87
}
88
89
- bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX,
90
- &local_err);
91
+ backing_filename = bdrv_get_full_backing_filename(bs, &local_err);
92
if (local_err) {
93
ret = -EINVAL;
94
error_propagate(errp, local_err);
95
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
96
qdict_put_str(options, "driver", bs->backing_format);
97
}
54
}
98
55
99
- backing_hd = bdrv_open_inherit(*backing_filename ? backing_filename : NULL,
56
/* Re-enable things in child-to-parent order */
100
- reference, options, 0, bs, &child_backing,
57
- bdrv_drain_invoke(bs, false);
101
- errp);
58
+ bdrv_drain_invoke(bs, false, false);
102
+ backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
59
bdrv_parent_drained_end(bs);
103
+ &child_backing, errp);
60
aio_enable_external(bdrv_get_aio_context(bs));
104
if (!backing_hd) {
61
}
105
bs->open_flags |= BDRV_O_NO_BACKING;
62
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
106
error_prepend(errp, "Could not open backing file: ");
63
aio_context_acquire(aio_context);
107
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
64
aio_disable_external(aio_context);
108
int is_protocol = 0;
65
bdrv_parent_drained_begin(bs);
109
BlockDriverState *curr_bs = NULL;
66
- bdrv_drain_invoke(bs, true);
110
BlockDriverState *retval = NULL;
67
+ bdrv_drain_invoke(bs, true, true);
111
- Error *local_error = NULL;
68
aio_context_release(aio_context);
112
69
113
if (!bs || !bs->drv || !backing_file) {
70
if (!g_slist_find(aio_ctxs, aio_context)) {
114
return NULL;
71
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
115
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
72
116
/* If either of the filename paths is actually a protocol, then
73
/* Re-enable things in child-to-parent order */
117
* compare unmodified paths; otherwise make paths relative */
74
aio_context_acquire(aio_context);
118
if (is_protocol || path_has_protocol(curr_bs->backing_file)) {
75
- bdrv_drain_invoke(bs, false);
119
+ char *backing_file_full_ret;
76
+ bdrv_drain_invoke(bs, false, true);
120
+
77
bdrv_parent_drained_end(bs);
121
if (strcmp(backing_file, curr_bs->backing_file) == 0) {
78
aio_enable_external(aio_context);
122
retval = curr_bs->backing->bs;
79
aio_context_release(aio_context);
123
break;
124
}
125
/* Also check against the full backing filename for the image */
126
- bdrv_get_full_backing_filename(curr_bs, backing_file_full, PATH_MAX,
127
- &local_error);
128
- if (local_error == NULL) {
129
- if (strcmp(backing_file, backing_file_full) == 0) {
130
+ backing_file_full_ret = bdrv_get_full_backing_filename(curr_bs,
131
+ NULL);
132
+ if (backing_file_full_ret) {
133
+ bool equal = strcmp(backing_file, backing_file_full_ret) == 0;
134
+ g_free(backing_file_full_ret);
135
+ if (equal) {
136
retval = curr_bs->backing->bs;
137
break;
138
}
139
- } else {
140
- error_free(local_error);
141
- local_error = NULL;
142
}
143
} else {
144
/* If not an absolute filename path, make it relative to the current
145
diff --git a/block/qapi.c b/block/qapi.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/block/qapi.c
148
+++ b/block/qapi.c
149
@@ -XXX,XX +XXX,XX @@ void bdrv_query_image_info(BlockDriverState *bs,
150
151
backing_filename = bs->backing_file;
152
if (backing_filename[0] != '\0') {
153
- char *backing_filename2 = g_malloc0(PATH_MAX);
154
+ char *backing_filename2;
155
info->backing_filename = g_strdup(backing_filename);
156
info->has_backing_filename = true;
157
- bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err);
158
- if (err) {
159
- /* Can't reconstruct the full backing filename, so we must omit
160
- * this field and apply a Best Effort to this query. */
161
- g_free(backing_filename2);
162
- backing_filename2 = NULL;
163
- error_free(err);
164
- err = NULL;
165
- }
166
+ backing_filename2 = bdrv_get_full_backing_filename(bs, NULL);
167
168
/* Always report the full_backing_filename if present, even if it's the
169
* same as backing_filename. That they are same is useful info. */
170
--
80
--
171
2.20.1
81
2.13.6
172
82
173
83
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@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 follow-up patches will rework the way bs->full_open_options is
6
Also, add a backing file to the test node to test whether the operations
4
refreshed in bdrv_refresh_filename(). The new implementation will remove
7
work recursively.
5
the need for the block drivers' bdrv_refresh_filename() implementations
6
to set bs->full_open_options; instead, it will be generic and use static
7
information from each block driver.
8
8
9
However, by implementing bdrv_gather_child_options(), block drivers will
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
still be able to override the way the full_open_options of their
10
---
11
children are incorporated into their own.
11
tests/test-bdrv-drain.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-----
12
1 file changed, 62 insertions(+), 7 deletions(-)
12
13
13
We need to implement this function for VMDK because we have to prevent
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
the generic implementation from gathering the options of all children:
15
It is not possible to specify options for the extents through the
16
runtime options.
17
18
For quorum, the child names that would be used by the generic
19
implementation and the ones that we actually (currently) want to use
20
differ. See quorum_gather_child_options() for more information.
21
22
Note that both of these are cases which are not ideal: In case of VMDK
23
it would probably be nice to be able to specify options for all extents.
24
In case of quorum, the current runtime option structure is simply broken
25
and needs to be fixed (but that is left for another patch).
26
27
Signed-off-by: Max Reitz <mreitz@redhat.com>
28
Reviewed-by: Alberto Garcia <berto@igalia.com>
29
Message-id: 20190201192935.18394-23-mreitz@redhat.com
30
Signed-off-by: Max Reitz <mreitz@redhat.com>
31
---
32
include/block/block_int.h | 24 +++++++++++++++++++++++
33
block/quorum.c | 40 +++++++++++++++++++++++++++++++++++++++
34
block/vmdk.c | 19 +++++++++++++++++++
35
3 files changed, 83 insertions(+)
36
37
diff --git a/include/block/block_int.h b/include/block/block_int.h
38
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block_int.h
16
--- a/tests/test-bdrv-drain.c
40
+++ b/include/block/block_int.h
17
+++ b/tests/test-bdrv-drain.c
41
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
18
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = {
42
19
43
void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
20
.bdrv_co_drain_begin = bdrv_test_co_drain_begin,
44
21
.bdrv_co_drain_end = bdrv_test_co_drain_end,
45
+ /*
46
+ * Gathers the open options for all children into @target.
47
+ * A simple format driver (without backing file support) might
48
+ * implement this function like this:
49
+ *
50
+ * QINCREF(bs->file->bs->full_open_options);
51
+ * qdict_put(target, "file", bs->file->bs->full_open_options);
52
+ *
53
+ * If not specified, the generic implementation will simply put
54
+ * all children's options under their respective name.
55
+ *
56
+ * @backing_overridden is true when bs->backing seems not to be
57
+ * the child that would result from opening bs->backing_file.
58
+ * Therefore, if it is true, the backing child's options should be
59
+ * gathered; otherwise, there is no need since the backing child
60
+ * is the one implied by the image header.
61
+ *
62
+ * Note that ideally this function would not be needed. Every
63
+ * block driver which implements it is probably doing something
64
+ * shady regarding its runtime option structure.
65
+ */
66
+ void (*bdrv_gather_child_options)(BlockDriverState *bs, QDict *target,
67
+ bool backing_overridden);
68
+
22
+
69
/*
23
+ .bdrv_child_perm = bdrv_format_default_perms,
70
* Returns an allocated string which is the directory name of this BDS: It
24
};
71
* will be used to make relative filenames absolute by prepending this
25
72
diff --git a/block/quorum.c b/block/quorum.c
26
static void aio_ret_cb(void *opaque, int ret)
73
index XXXXXXX..XXXXXXX 100644
27
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
74
--- a/block/quorum.c
28
*aio_ret = ret;
75
+++ b/block/quorum.c
76
@@ -XXX,XX +XXX,XX @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
77
bs->full_open_options = opts;
78
}
29
}
79
30
80
+static void quorum_gather_child_options(BlockDriverState *bs, QDict *target,
31
-static void test_drv_cb_drain_all(void)
81
+ bool backing_overridden)
32
+enum drain_type {
33
+ BDRV_DRAIN_ALL,
34
+ BDRV_DRAIN,
35
+};
36
+
37
+static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
82
+{
38
+{
83
+ BDRVQuorumState *s = bs->opaque;
39
+ switch (drain_type) {
84
+ QList *children_list;
40
+ case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
85
+ int i;
41
+ case BDRV_DRAIN: bdrv_drained_begin(bs); break;
86
+
42
+ default: g_assert_not_reached();
87
+ /*
88
+ * The generic implementation for gathering child options in
89
+ * bdrv_refresh_filename() would use the names of the children
90
+ * as specified for bdrv_open_child() or bdrv_attach_child(),
91
+ * which is "children.%u" with %u being a value
92
+ * (s->next_child_index) that is incremented each time a new child
93
+ * is added (and never decremented). Since children can be
94
+ * deleted at runtime, there may be gaps in that enumeration.
95
+ * When creating a new quorum BDS and specifying the children for
96
+ * it through runtime options, the enumeration used there may not
97
+ * have any gaps, though.
98
+ *
99
+ * Therefore, we have to create a new gap-less enumeration here
100
+ * (which we can achieve by simply putting all of the children's
101
+ * full_open_options into a QList).
102
+ *
103
+ * XXX: Note that there are issues with the current child option
104
+ * structure quorum uses (such as the fact that children do
105
+ * not really have unique permanent names). Therefore, this
106
+ * is going to have to change in the future and ideally we
107
+ * want quorum to be covered by the generic implementation.
108
+ */
109
+
110
+ children_list = qlist_new();
111
+ qdict_put(target, "children", children_list);
112
+
113
+ for (i = 0; i < s->num_children; i++) {
114
+ qlist_append(children_list,
115
+ qobject_ref(s->children[i]->bs->full_open_options));
116
+ }
43
+ }
117
+}
44
+}
118
+
45
+
119
static char *quorum_dirname(BlockDriverState *bs, Error **errp)
46
+static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
120
{
121
/* In general, there are multiple BDSs with different dirnames below this
122
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_quorum = {
123
.bdrv_open = quorum_open,
124
.bdrv_close = quorum_close,
125
.bdrv_refresh_filename = quorum_refresh_filename,
126
+ .bdrv_gather_child_options = quorum_gather_child_options,
127
.bdrv_dirname = quorum_dirname,
128
129
.bdrv_co_flush_to_disk = quorum_co_flush,
130
diff --git a/block/vmdk.c b/block/vmdk.c
131
index XXXXXXX..XXXXXXX 100644
132
--- a/block/vmdk.c
133
+++ b/block/vmdk.c
134
@@ -XXX,XX +XXX,XX @@
135
#include "qapi/error.h"
136
#include "block/block_int.h"
137
#include "sysemu/block-backend.h"
138
+#include "qapi/qmp/qdict.h"
139
#include "qapi/qmp/qerror.h"
140
#include "qemu/error-report.h"
141
#include "qemu/module.h"
142
@@ -XXX,XX +XXX,XX @@ static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
143
return 0;
144
}
145
146
+static void vmdk_gather_child_options(BlockDriverState *bs, QDict *target,
147
+ bool backing_overridden)
148
+{
47
+{
149
+ /* No children but file and backing can be explicitly specified (TODO) */
48
+ switch (drain_type) {
150
+ qdict_put(target, "file",
49
+ case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
151
+ qobject_ref(bs->file->bs->full_open_options));
50
+ case BDRV_DRAIN: bdrv_drained_end(bs); break;
152
+
51
+ default: g_assert_not_reached();
153
+ if (backing_overridden) {
154
+ if (bs->backing) {
155
+ qdict_put(target, "backing",
156
+ qobject_ref(bs->backing->bs->full_open_options));
157
+ } else {
158
+ qdict_put_null(target, "backing");
159
+ }
160
+ }
52
+ }
161
+}
53
+}
162
+
54
+
163
static QemuOptsList vmdk_create_opts = {
55
+static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
164
.name = "vmdk-create-opts",
56
{
165
.head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head),
57
BlockBackend *blk;
166
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = {
58
- BlockDriverState *bs;
167
.bdrv_get_specific_info = vmdk_get_specific_info,
59
- BDRVTestState *s;
168
.bdrv_refresh_limits = vmdk_refresh_limits,
60
+ BlockDriverState *bs, *backing;
169
.bdrv_get_info = vmdk_get_info,
61
+ BDRVTestState *s, *backing_s;
170
+ .bdrv_gather_child_options = vmdk_gather_child_options,
62
BlockAIOCB *acb;
171
63
int aio_ret;
172
.supports_backing = true,
64
173
.create_opts = &vmdk_create_opts,
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
}
174
--
136
--
175
2.20.1
137
2.13.6
176
138
177
139
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
This is currently only working correctly for bdrv_drain(), not for
2
bdrv_drain_all(). Leave a comment for the drain_all case, we'll address
3
it later.
2
4
3
LUKS encryption reserves clusters for its own payload data. The size of
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
this area must be included in the qemu-img measure calculation so that
6
---
5
we arrive at the correct minimum required image size.
7
tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 45 insertions(+)
6
9
7
(Ab)use the qcrypto_block_create() API to determine the payload
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
8
overhead. We discard the payload data that qcrypto thinks will be
9
written to the image.
10
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-id: 20190218104525.23674-2-stefanha@redhat.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-
17
1 file changed, 71 insertions(+), 1 deletion(-)
18
19
diff --git a/block/qcow2.c b/block/qcow2.c
20
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.c
12
--- a/tests/test-bdrv-drain.c
22
+++ b/block/qcow2.c
13
+++ b/tests/test-bdrv-drain.c
23
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
14
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
24
return ret;
15
test_drv_cb_common(BDRV_DRAIN, false);
25
}
16
}
26
17
27
+static ssize_t qcow2_measure_crypto_hdr_init_func(QCryptoBlock *block,
18
+static void test_quiesce_common(enum drain_type drain_type, bool recursive)
28
+ size_t headerlen, void *opaque, Error **errp)
29
+{
19
+{
30
+ size_t *headerlenp = opaque;
20
+ BlockBackend *blk;
21
+ BlockDriverState *bs, *backing;
31
+
22
+
32
+ /* Stash away the payload size */
23
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
33
+ *headerlenp = headerlen;
24
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
34
+ return 0;
25
+ &error_abort);
26
+ blk_insert_bs(blk, bs, &error_abort);
27
+
28
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
29
+ bdrv_set_backing_hd(bs, backing, &error_abort);
30
+
31
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
32
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
33
+
34
+ do_drain_begin(drain_type, bs);
35
+
36
+ g_assert_cmpint(bs->quiesce_counter, ==, 1);
37
+ g_assert_cmpint(backing->quiesce_counter, ==, !!recursive);
38
+
39
+ do_drain_end(drain_type, bs);
40
+
41
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
43
+
44
+ bdrv_unref(backing);
45
+ bdrv_unref(bs);
46
+ blk_unref(blk);
35
+}
47
+}
36
+
48
+
37
+static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block,
49
+static void test_quiesce_drain_all(void)
38
+ size_t offset, const uint8_t *buf, size_t buflen,
39
+ void *opaque, Error **errp)
40
+{
50
+{
41
+ /* Discard the bytes, we're not actually writing to an image */
51
+ // XXX drain_all doesn't quiesce
42
+ return buflen;
52
+ //test_quiesce_common(BDRV_DRAIN_ALL, true);
43
+}
53
+}
44
+
54
+
45
+/* Determine the number of bytes for the LUKS payload */
55
+static void test_quiesce_drain(void)
46
+static bool qcow2_measure_luks_headerlen(QemuOpts *opts, size_t *len,
47
+ Error **errp)
48
+{
56
+{
49
+ QDict *opts_qdict;
57
+ test_quiesce_common(BDRV_DRAIN, false);
50
+ QDict *cryptoopts_qdict;
51
+ QCryptoBlockCreateOptions *cryptoopts;
52
+ QCryptoBlock *crypto;
53
+
54
+ /* Extract "encrypt." options into a qdict */
55
+ opts_qdict = qemu_opts_to_qdict(opts, NULL);
56
+ qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt.");
57
+ qobject_unref(opts_qdict);
58
+
59
+ /* Build QCryptoBlockCreateOptions object from qdict */
60
+ qdict_put_str(cryptoopts_qdict, "format", "luks");
61
+ cryptoopts = block_crypto_create_opts_init(cryptoopts_qdict, errp);
62
+ qobject_unref(cryptoopts_qdict);
63
+ if (!cryptoopts) {
64
+ return false;
65
+ }
66
+
67
+ /* Fake LUKS creation in order to determine the payload size */
68
+ crypto = qcrypto_block_create(cryptoopts, "encrypt.",
69
+ qcow2_measure_crypto_hdr_init_func,
70
+ qcow2_measure_crypto_hdr_write_func,
71
+ len, errp);
72
+ qapi_free_QCryptoBlockCreateOptions(cryptoopts);
73
+ if (!crypto) {
74
+ return false;
75
+ }
76
+
77
+ qcrypto_block_free(crypto);
78
+ return true;
79
+}
58
+}
80
+
59
+
81
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
60
int main(int argc, char **argv)
82
Error **errp)
83
{
61
{
84
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
62
bdrv_init();
85
uint64_t virtual_size; /* disk size as seen by guest */
63
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
86
uint64_t refcount_bits;
64
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
87
uint64_t l2_tables;
65
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
88
+ uint64_t luks_payload_size = 0;
66
89
size_t cluster_size;
67
+ g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
90
int version;
68
+ g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
91
char *optstr;
92
PreallocMode prealloc;
93
bool has_backing_file;
94
+ bool has_luks;
95
96
/* Parse image creation options */
97
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
98
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
99
has_backing_file = !!optstr;
100
g_free(optstr);
101
102
+ optstr = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
103
+ has_luks = optstr && strcmp(optstr, "luks") == 0;
104
+ g_free(optstr);
105
+
69
+
106
+ if (has_luks) {
70
return g_test_run();
107
+ size_t headerlen;
71
}
108
+
109
+ if (!qcow2_measure_luks_headerlen(opts, &headerlen, &local_err)) {
110
+ goto err;
111
+ }
112
+
113
+ luks_payload_size = ROUND_UP(headerlen, cluster_size);
114
+ }
115
+
116
virtual_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
117
virtual_size = ROUND_UP(virtual_size, cluster_size);
118
119
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
120
info = g_new(BlockMeasureInfo, 1);
121
info->fully_allocated =
122
qcow2_calc_prealloc_size(virtual_size, cluster_size,
123
- ctz32(refcount_bits));
124
+ ctz32(refcount_bits)) + luks_payload_size;
125
126
/* Remove data clusters that are not required. This overestimates the
127
* required size because metadata needed for the fully allocated file is
128
--
72
--
129
2.20.1
73
2.13.6
130
74
131
75
diff view generated by jsdifflib
1
For some users of BlockBackends, just increasing the in_flight counter
1
Block jobs already paused themselves when their main BlockBackend
2
is easier than implementing separate handlers in BlockDevOps. Make the
2
entered a drained section. This is not good enough: We also want to
3
helper functions for this public.
3
pause a block job and may not submit new requests if, for example, the
4
mirror target node should be drained.
5
6
This implements .drained_begin/end callbacks in child_job in order to
7
consider all block nodes related to the job, and removes the
8
BlockBackend callbacks which are unnecessary now because the root of the
9
job main BlockBackend is always referenced with a child_job, too.
4
10
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
12
---
7
include/sysemu/block-backend.h | 2 ++
13
blockjob.c | 22 +++++++++-------------
8
block/block-backend.c | 4 ++--
14
1 file changed, 9 insertions(+), 13 deletions(-)
9
2 files changed, 4 insertions(+), 2 deletions(-)
10
15
11
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
16
diff --git a/blockjob.c b/blockjob.c
12
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
13
--- a/include/sysemu/block-backend.h
18
--- a/blockjob.c
14
+++ b/include/sysemu/block-backend.h
19
+++ b/blockjob.c
15
@@ -XXX,XX +XXX,XX @@ int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
20
@@ -XXX,XX +XXX,XX @@ static char *child_job_get_parent_desc(BdrvChild *c)
16
int blk_co_flush(BlockBackend *blk);
21
job->id);
17
int blk_flush(BlockBackend *blk);
18
int blk_commit_all(void);
19
+void blk_inc_in_flight(BlockBackend *blk);
20
+void blk_dec_in_flight(BlockBackend *blk);
21
void blk_drain(BlockBackend *blk);
22
void blk_drain_all(void);
23
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
24
diff --git a/block/block-backend.c b/block/block-backend.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block/block-backend.c
27
+++ b/block/block-backend.c
28
@@ -XXX,XX +XXX,XX @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
29
return bdrv_make_zero(blk->root, flags);
30
}
22
}
31
23
32
-static void blk_inc_in_flight(BlockBackend *blk)
24
-static const BdrvChildRole child_job = {
33
+void blk_inc_in_flight(BlockBackend *blk)
25
- .get_parent_desc = child_job_get_parent_desc,
26
- .stay_at_node = true,
27
-};
28
-
29
-static void block_job_drained_begin(void *opaque)
30
+static void child_job_drained_begin(BdrvChild *c)
34
{
31
{
35
atomic_inc(&blk->in_flight);
32
- BlockJob *job = opaque;
33
+ BlockJob *job = c->opaque;
34
block_job_pause(job);
36
}
35
}
37
36
38
-static void blk_dec_in_flight(BlockBackend *blk)
37
-static void block_job_drained_end(void *opaque)
39
+void blk_dec_in_flight(BlockBackend *blk)
38
+static void child_job_drained_end(BdrvChild *c)
40
{
39
{
41
atomic_dec(&blk->in_flight);
40
- BlockJob *job = opaque;
42
aio_wait_kick();
41
+ BlockJob *job = c->opaque;
42
block_job_resume(job);
43
}
44
45
-static const BlockDevOps block_job_dev_ops = {
46
- .drained_begin = block_job_drained_begin,
47
- .drained_end = block_job_drained_end,
48
+static const BdrvChildRole child_job = {
49
+ .get_parent_desc = child_job_get_parent_desc,
50
+ .drained_begin = child_job_drained_begin,
51
+ .drained_end = child_job_drained_end,
52
+ .stay_at_node = true,
53
};
54
55
void block_job_remove_all_bdrv(BlockJob *job)
56
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
57
block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
58
bs->job = job;
59
60
- blk_set_dev_ops(blk, &block_job_dev_ops, job);
61
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
62
63
QLIST_INSERT_HEAD(&block_jobs, job, job_list);
43
--
64
--
44
2.20.1
65
2.13.6
45
66
46
67
diff view generated by jsdifflib
1
The only caller of nbd_read_eof() is nbd_receive_reply(), so it doesn't
1
Block jobs must be paused if any of the involved nodes are drained.
2
have to live in the header file, but can move next to its caller.
3
4
Also add the missing coroutine_fn to the function and its caller.
5
2
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
4
---
9
include/block/nbd.h | 3 ++-
5
tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++
10
nbd/nbd-internal.h | 19 -------------------
6
1 file changed, 121 insertions(+)
11
nbd/client.c | 22 +++++++++++++++++++++-
12
3 files changed, 23 insertions(+), 21 deletions(-)
13
7
14
diff --git a/include/block/nbd.h b/include/block/nbd.h
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
15
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/nbd.h
10
--- a/tests/test-bdrv-drain.c
17
+++ b/include/block/nbd.h
11
+++ b/tests/test-bdrv-drain.c
18
@@ -XXX,XX +XXX,XX @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
19
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
20
Error **errp);
21
int nbd_send_request(QIOChannel *ioc, NBDRequest *request);
22
-int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp);
23
+int coroutine_fn nbd_receive_reply(QIOChannel *ioc, NBDReply *reply,
24
+ Error **errp);
25
int nbd_client(int fd);
26
int nbd_disconnect(int fd);
27
int nbd_errno_to_system_errno(int err);
28
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/nbd/nbd-internal.h
31
+++ b/nbd/nbd-internal.h
32
@@ -XXX,XX +XXX,XX @@
12
@@ -XXX,XX +XXX,XX @@
33
#define NBD_SET_TIMEOUT _IO(0xab, 9)
13
34
#define NBD_SET_FLAGS _IO(0xab, 10)
14
#include "qemu/osdep.h"
35
15
#include "block/block.h"
36
-/* nbd_read_eof
16
+#include "block/blockjob_int.h"
37
- * Tries to read @size bytes from @ioc.
17
#include "sysemu/block-backend.h"
38
- * Returns 1 on success
18
#include "qapi/error.h"
39
- * 0 on eof, when no data was read (errp is not set)
19
40
- * negative errno on failure (errp is set)
20
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
41
- */
21
test_quiesce_common(BDRV_DRAIN, false);
42
-static inline int nbd_read_eof(QIOChannel *ioc, void *buffer, size_t size,
43
- Error **errp)
44
-{
45
- int ret;
46
-
47
- assert(size);
48
- ret = qio_channel_read_all_eof(ioc, buffer, size, errp);
49
- if (ret < 0) {
50
- ret = -EIO;
51
- }
52
- return ret;
53
-}
54
-
55
/* nbd_write
56
* Writes @size bytes to @ioc. Returns 0 on success.
57
*/
58
diff --git a/nbd/client.c b/nbd/client.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/nbd/client.c
61
+++ b/nbd/client.c
62
@@ -XXX,XX +XXX,XX @@ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc,
63
return 0;
64
}
22
}
65
23
66
+/* nbd_read_eof
24
+
67
+ * Tries to read @size bytes from @ioc.
25
+typedef struct TestBlockJob {
68
+ * Returns 1 on success
26
+ BlockJob common;
69
+ * 0 on eof, when no data was read (errp is not set)
27
+ bool should_complete;
70
+ * negative errno on failure (errp is set)
28
+} TestBlockJob;
71
+ */
29
+
72
+static inline int coroutine_fn
30
+static void test_job_completed(BlockJob *job, void *opaque)
73
+nbd_read_eof(QIOChannel *ioc, void *buffer, size_t size, Error **errp)
74
+{
31
+{
32
+ block_job_completed(job, 0);
33
+}
34
+
35
+static void coroutine_fn test_job_start(void *opaque)
36
+{
37
+ TestBlockJob *s = opaque;
38
+
39
+ while (!s->should_complete) {
40
+ block_job_sleep_ns(&s->common, 100000);
41
+ }
42
+
43
+ block_job_defer_to_main_loop(&s->common, test_job_completed, NULL);
44
+}
45
+
46
+static void test_job_complete(BlockJob *job, Error **errp)
47
+{
48
+ TestBlockJob *s = container_of(job, TestBlockJob, common);
49
+ s->should_complete = true;
50
+}
51
+
52
+BlockJobDriver test_job_driver = {
53
+ .instance_size = sizeof(TestBlockJob),
54
+ .start = test_job_start,
55
+ .complete = test_job_complete,
56
+};
57
+
58
+static void test_blockjob_common(enum drain_type drain_type)
59
+{
60
+ BlockBackend *blk_src, *blk_target;
61
+ BlockDriverState *src, *target;
62
+ BlockJob *job;
75
+ int ret;
63
+ int ret;
76
+
64
+
77
+ assert(size);
65
+ src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR,
78
+ ret = qio_channel_read_all_eof(ioc, buffer, size, errp);
66
+ &error_abort);
79
+ if (ret < 0) {
67
+ blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
80
+ ret = -EIO;
68
+ blk_insert_bs(blk_src, src, &error_abort);
69
+
70
+ target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
71
+ &error_abort);
72
+ blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
73
+ blk_insert_bs(blk_target, target, &error_abort);
74
+
75
+ job = block_job_create("job0", &test_job_driver, src, 0, BLK_PERM_ALL, 0,
76
+ 0, NULL, NULL, &error_abort);
77
+ block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
78
+ block_job_start(job);
79
+
80
+ g_assert_cmpint(job->pause_count, ==, 0);
81
+ g_assert_false(job->paused);
82
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
83
+
84
+ do_drain_begin(drain_type, src);
85
+
86
+ if (drain_type == BDRV_DRAIN_ALL) {
87
+ /* bdrv_drain_all() drains both src and target, and involves an
88
+ * additional block_job_pause_all() */
89
+ g_assert_cmpint(job->pause_count, ==, 3);
90
+ } else {
91
+ g_assert_cmpint(job->pause_count, ==, 1);
81
+ }
92
+ }
82
+ return ret;
93
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
94
+ /* g_assert_true(job->paused); */
95
+ g_assert_false(job->busy); /* The job is paused */
96
+
97
+ do_drain_end(drain_type, src);
98
+
99
+ g_assert_cmpint(job->pause_count, ==, 0);
100
+ g_assert_false(job->paused);
101
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
102
+
103
+ do_drain_begin(drain_type, target);
104
+
105
+ if (drain_type == BDRV_DRAIN_ALL) {
106
+ /* bdrv_drain_all() drains both src and target, and involves an
107
+ * additional block_job_pause_all() */
108
+ g_assert_cmpint(job->pause_count, ==, 3);
109
+ } else {
110
+ g_assert_cmpint(job->pause_count, ==, 1);
111
+ }
112
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
113
+ /* g_assert_true(job->paused); */
114
+ g_assert_false(job->busy); /* The job is paused */
115
+
116
+ do_drain_end(drain_type, target);
117
+
118
+ g_assert_cmpint(job->pause_count, ==, 0);
119
+ g_assert_false(job->paused);
120
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
121
+
122
+ ret = block_job_complete_sync(job, &error_abort);
123
+ g_assert_cmpint(ret, ==, 0);
124
+
125
+ blk_unref(blk_src);
126
+ blk_unref(blk_target);
127
+ bdrv_unref(src);
128
+ bdrv_unref(target);
83
+}
129
+}
84
+
130
+
85
/* nbd_receive_reply
131
+static void test_blockjob_drain_all(void)
86
* Returns 1 on success
132
+{
87
* 0 on eof, when no data was read (errp is not set)
133
+ test_blockjob_common(BDRV_DRAIN_ALL);
88
* negative errno on failure (errp is set)
134
+}
89
*/
135
+
90
-int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)
136
+static void test_blockjob_drain(void)
91
+int coroutine_fn nbd_receive_reply(QIOChannel *ioc, NBDReply *reply,
137
+{
92
+ Error **errp)
138
+ test_blockjob_common(BDRV_DRAIN);
139
+}
140
+
141
int main(int argc, char **argv)
93
{
142
{
94
int ret;
143
bdrv_init();
95
const char *type;
144
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
145
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
146
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
147
148
+ g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
149
+ g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
150
+
151
return g_test_run();
152
}
96
--
153
--
97
2.20.1
154
2.13.6
98
155
99
156
diff view generated by jsdifflib
1
virtio_blk_dma_restart_bh() submits new requests, so in order to make
1
Block jobs are already paused using the BdrvChildRole drain callbacks,
2
sure that these requests are not started inside a drained section of the
2
so we don't need an additional block_job_pause_all() call.
3
attached BlockBackend, we need to make sure that draining the
4
BlockBackend waits for the BH to be executed.
5
6
This BH is still questionable because its scheduled in the main thread
7
instead of the configured iothread. Leave a FIXME comment for this.
8
9
But with this fix, enabling the data plane at least waits for these
10
requests (in bdrv_set_aio_context()) instead of changing the AioContext
11
under their feet and making them run in the wrong thread, causing
12
crashes and failures (e.g. due to missing locking).
13
3
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
5
---
16
hw/block/virtio-blk.c | 4 ++++
6
block/io.c | 4 ----
17
1 file changed, 4 insertions(+)
7
tests/test-bdrv-drain.c | 10 ++++------
8
2 files changed, 4 insertions(+), 10 deletions(-)
18
9
19
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
10
diff --git a/block/io.c b/block/io.c
20
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/block/virtio-blk.c
12
--- a/block/io.c
22
+++ b/hw/block/virtio-blk.c
13
+++ b/block/io.c
23
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_dma_restart_bh(void *opaque)
14
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
24
if (mrb.num_reqs) {
15
* context. */
25
virtio_blk_submit_multireq(s->blk, &mrb);
16
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
17
18
- block_job_pause_all();
19
-
20
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
21
AioContext *aio_context = bdrv_get_aio_context(bs);
22
23
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
24
aio_enable_external(aio_context);
25
aio_context_release(aio_context);
26
}
26
}
27
+ blk_dec_in_flight(s->conf.conf.blk);
27
-
28
aio_context_release(blk_get_aio_context(s->conf.conf.blk));
28
- block_job_resume_all();
29
}
29
}
30
30
31
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_dma_restart_cb(void *opaque, int running,
31
void bdrv_drain_all(void)
32
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/tests/test-bdrv-drain.c
35
+++ b/tests/test-bdrv-drain.c
36
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
37
do_drain_begin(drain_type, src);
38
39
if (drain_type == BDRV_DRAIN_ALL) {
40
- /* bdrv_drain_all() drains both src and target, and involves an
41
- * additional block_job_pause_all() */
42
- g_assert_cmpint(job->pause_count, ==, 3);
43
+ /* bdrv_drain_all() drains both src and target */
44
+ g_assert_cmpint(job->pause_count, ==, 2);
45
} else {
46
g_assert_cmpint(job->pause_count, ==, 1);
32
}
47
}
33
48
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
34
if (!s->bh) {
49
do_drain_begin(drain_type, target);
35
+ /* FIXME The data plane is not started yet, so these requests are
50
36
+ * processed in the main thread. */
51
if (drain_type == BDRV_DRAIN_ALL) {
37
s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk),
52
- /* bdrv_drain_all() drains both src and target, and involves an
38
virtio_blk_dma_restart_bh, s);
53
- * additional block_job_pause_all() */
39
+ blk_inc_in_flight(s->conf.conf.blk);
54
- g_assert_cmpint(job->pause_count, ==, 3);
40
qemu_bh_schedule(s->bh);
55
+ /* bdrv_drain_all() drains both src and target */
56
+ g_assert_cmpint(job->pause_count, ==, 2);
57
} else {
58
g_assert_cmpint(job->pause_count, ==, 1);
41
}
59
}
42
}
43
--
60
--
44
2.20.1
61
2.13.6
45
62
46
63
diff view generated by jsdifflib
1
Similar to how qemu_co_sleep_ns() allows preemption from an external
1
bdrv_do_drained_begin() restricts the call of parent callbacks and
2
coroutine entry, allow reentering qio_channel_yield() early.
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
include/io/channel.h | 9 ++++++---
9
block/io.c | 12 +++++++-----
7
io/channel.c | 10 ++++++++++
10
1 file changed, 7 insertions(+), 5 deletions(-)
8
2 files changed, 16 insertions(+), 3 deletions(-)
9
11
10
diff --git a/include/io/channel.h b/include/io/channel.h
12
diff --git a/block/io.c b/block/io.c
11
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
12
--- a/include/io/channel.h
14
--- a/block/io.c
13
+++ b/include/io/channel.h
15
+++ b/block/io.c
14
@@ -XXX,XX +XXX,XX @@ void qio_channel_detach_aio_context(QIOChannel *ioc);
16
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
15
* addition, no two coroutine can be waiting on the same condition
17
16
* and channel at the same time.
18
void bdrv_drained_end(BlockDriverState *bs)
17
*
19
{
18
- * This must only be called from coroutine context
20
+ int old_quiesce_counter;
19
+ * This must only be called from coroutine context. It is safe to
21
+
20
+ * reenter the coroutine externally while it is waiting; in this
22
if (qemu_in_coroutine()) {
21
+ * case the function will return even if @condition is not yet
23
bdrv_co_yield_to_drain(bs, false);
22
+ * available.
24
return;
23
*/
24
-void qio_channel_yield(QIOChannel *ioc,
25
- GIOCondition condition);
26
+void coroutine_fn qio_channel_yield(QIOChannel *ioc,
27
+ GIOCondition condition);
28
29
/**
30
* qio_channel_wait:
31
diff --git a/io/channel.c b/io/channel.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/io/channel.c
34
+++ b/io/channel.c
35
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qio_channel_yield(QIOChannel *ioc,
36
}
25
}
37
qio_channel_set_aio_fd_handlers(ioc);
26
assert(bs->quiesce_counter > 0);
38
qemu_coroutine_yield();
27
- if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
39
+
28
- return;
40
+ /* Allow interrupting the operation by reentering the coroutine other than
29
- }
41
+ * through the aio_fd_handlers. */
30
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
42
+ if (condition == G_IO_IN && ioc->read_coroutine) {
31
43
+ ioc->read_coroutine = NULL;
32
/* Re-enable things in child-to-parent order */
44
+ qio_channel_set_aio_fd_handlers(ioc);
33
bdrv_drain_invoke(bs, false, false);
45
+ } else if (condition == G_IO_OUT && ioc->write_coroutine) {
34
- bdrv_parent_drained_end(bs);
46
+ ioc->write_coroutine = NULL;
35
- aio_enable_external(bdrv_get_aio_context(bs));
47
+ qio_channel_set_aio_fd_handlers(ioc);
36
+ if (old_quiesce_counter == 1) {
37
+ bdrv_parent_drained_end(bs);
38
+ aio_enable_external(bdrv_get_aio_context(bs));
48
+ }
39
+ }
49
}
40
}
50
41
51
42
/*
52
--
43
--
53
2.20.1
44
2.13.6
54
45
55
46
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
3
tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
4
1 file changed, 57 insertions(+)
2
5
3
Instead of having every block driver which implements
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
4
bdrv_refresh_filename() copy all of the strong runtime options over to
5
bs->full_open_options, implement this process generically in
6
bdrv_refresh_filename().
7
8
This patch only adds this new generic implementation, it does not remove
9
the old functionality. This is done in a follow-up patch.
10
11
With this patch, some superfluous information (that should never have
12
been there) may be removed from some JSON filenames, as can be seen in
13
the change to iotests 110's and 228's reference outputs.
14
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Message-id: 20190201192935.18394-24-mreitz@redhat.com
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
block.c | 116 ++++++++++++++++++++++++++++++++++++-
20
tests/qemu-iotests/110.out | 2 +-
21
tests/qemu-iotests/228 | 7 ++-
22
tests/qemu-iotests/228.out | 2 +-
23
4 files changed, 121 insertions(+), 6 deletions(-)
24
25
diff --git a/block.c b/block.c
26
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
27
--- a/block.c
8
--- a/tests/test-bdrv-drain.c
28
+++ b/block.c
9
+++ b/tests/test-bdrv-drain.c
29
@@ -XXX,XX +XXX,XX @@ out:
10
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
30
return to_replace_bs;
11
enum drain_type {
12
BDRV_DRAIN_ALL,
13
BDRV_DRAIN,
14
+ DRAIN_TYPE_MAX,
15
};
16
17
static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
18
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
19
test_quiesce_common(BDRV_DRAIN, false);
31
}
20
}
32
21
33
+/**
22
+static void test_nested(void)
34
+ * Iterates through the list of runtime option keys that are said to
35
+ * be "strong" for a BDS. An option is called "strong" if it changes
36
+ * a BDS's data. For example, the null block driver's "size" and
37
+ * "read-zeroes" options are strong, but its "latency-ns" option is
38
+ * not.
39
+ *
40
+ * If a key returned by this function ends with a dot, all options
41
+ * starting with that prefix are strong.
42
+ */
43
+static const char *const *strong_options(BlockDriverState *bs,
44
+ const char *const *curopt)
45
+{
23
+{
46
+ static const char *const global_options[] = {
24
+ BlockBackend *blk;
47
+ "driver", "filename", NULL
25
+ BlockDriverState *bs, *backing;
48
+ };
26
+ BDRVTestState *s, *backing_s;
27
+ enum drain_type outer, inner;
49
+
28
+
50
+ if (!curopt) {
29
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
51
+ return &global_options[0];
30
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
52
+ }
31
+ &error_abort);
32
+ s = bs->opaque;
33
+ blk_insert_bs(blk, bs, &error_abort);
53
+
34
+
54
+ curopt++;
35
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
55
+ if (curopt == &global_options[ARRAY_SIZE(global_options) - 1] && bs->drv) {
36
+ backing_s = backing->opaque;
56
+ curopt = bs->drv->strong_runtime_opts;
37
+ bdrv_set_backing_hd(bs, backing, &error_abort);
57
+ }
58
+
38
+
59
+ return (curopt && *curopt) ? curopt : NULL;
39
+ for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
60
+}
40
+ for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
41
+ /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
42
+ int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
43
+ (inner != BDRV_DRAIN_ALL);
44
+ int backing_quiesce = 0;
45
+ int backing_cb_cnt = (outer != BDRV_DRAIN) +
46
+ (inner != BDRV_DRAIN);
61
+
47
+
62
+/**
48
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
63
+ * Copies all strong runtime options from bs->options to the given
49
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
64
+ * QDict. The set of strong option keys is determined by invoking
50
+ g_assert_cmpint(s->drain_count, ==, 0);
65
+ * strong_options().
51
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
66
+ *
67
+ * Returns true iff any strong option was present in bs->options (and
68
+ * thus copied to the target QDict) with the exception of "filename"
69
+ * and "driver". The caller is expected to use this value to decide
70
+ * whether the existence of strong options prevents the generation of
71
+ * a plain filename.
72
+ */
73
+static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
74
+{
75
+ bool found_any = false;
76
+ const char *const *option_name = NULL;
77
+
52
+
78
+ if (!bs->drv) {
53
+ do_drain_begin(outer, bs);
79
+ return false;
54
+ do_drain_begin(inner, bs);
80
+ }
81
+
55
+
82
+ while ((option_name = strong_options(bs, option_name))) {
56
+ g_assert_cmpint(bs->quiesce_counter, ==, bs_quiesce);
83
+ bool option_given = false;
57
+ g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce);
58
+ g_assert_cmpint(s->drain_count, ==, 2);
59
+ g_assert_cmpint(backing_s->drain_count, ==, backing_cb_cnt);
84
+
60
+
85
+ assert(strlen(*option_name) > 0);
61
+ do_drain_end(inner, bs);
86
+ if ((*option_name)[strlen(*option_name) - 1] != '.') {
62
+ do_drain_end(outer, bs);
87
+ QObject *entry = qdict_get(bs->options, *option_name);
88
+ if (!entry) {
89
+ continue;
90
+ }
91
+
63
+
92
+ qdict_put_obj(d, *option_name, qobject_ref(entry));
64
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
93
+ option_given = true;
65
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
94
+ } else {
66
+ g_assert_cmpint(s->drain_count, ==, 0);
95
+ const QDictEntry *entry;
67
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
96
+ for (entry = qdict_first(bs->options); entry;
97
+ entry = qdict_next(bs->options, entry))
98
+ {
99
+ if (strstart(qdict_entry_key(entry), *option_name, NULL)) {
100
+ qdict_put_obj(d, qdict_entry_key(entry),
101
+ qobject_ref(qdict_entry_value(entry)));
102
+ option_given = true;
103
+ }
104
+ }
105
+ }
106
+
107
+ /* While "driver" and "filename" need to be included in a JSON filename,
108
+ * their existence does not prohibit generation of a plain filename. */
109
+ if (!found_any && option_given &&
110
+ strcmp(*option_name, "driver") && strcmp(*option_name, "filename"))
111
+ {
112
+ found_any = true;
113
+ }
68
+ }
114
+ }
69
+ }
115
+
70
+
116
+ return found_any;
71
+ bdrv_unref(backing);
72
+ bdrv_unref(bs);
73
+ blk_unref(blk);
117
+}
74
+}
118
+
75
+
119
static bool append_open_options(QDict *d, BlockDriverState *bs)
76
120
{
77
typedef struct TestBlockJob {
121
const QDictEntry *entry;
78
BlockJob common;
122
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
79
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
123
bs->full_open_options = opts;
80
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
124
}
81
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
125
82
126
+ /* Gather the options QDict */
83
+ g_test_add_func("/bdrv-drain/nested", test_nested);
127
+ opts = qdict_new();
128
+ append_strong_runtime_options(opts, bs);
129
+
84
+
130
+ if (drv->bdrv_gather_child_options) {
85
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
131
+ /* Some block drivers may not want to present all of their children's
86
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
132
+ * options, or name them differently from BdrvChild.name */
133
+ drv->bdrv_gather_child_options(bs, opts, backing_overridden);
134
+ } else {
135
+ QLIST_FOREACH(child, &bs->children, next) {
136
+ if (child->role == &child_backing && !backing_overridden) {
137
+ /* We can skip the backing BDS if it has not been overridden */
138
+ continue;
139
+ }
140
+
141
+ qdict_put(opts, child->name,
142
+ qobject_ref(child->bs->full_open_options));
143
+ }
144
+
145
+ if (backing_overridden && !bs->backing) {
146
+ /* Force no backing file */
147
+ qdict_put_null(opts, "backing");
148
+ }
149
+ }
150
+
151
+ qobject_unref(bs->full_open_options);
152
+ bs->full_open_options = opts;
153
+
154
if (bs->exact_filename[0]) {
155
pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename);
156
- } else if (bs->full_open_options) {
157
+ } else {
158
QString *json = qobject_to_json(QOBJECT(bs->full_open_options));
159
snprintf(bs->filename, sizeof(bs->filename), "json:%s",
160
qstring_get_str(json));
161
diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out
162
index XXXXXXX..XXXXXXX 100644
163
--- a/tests/qemu-iotests/110.out
164
+++ b/tests/qemu-iotests/110.out
165
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.b
166
167
=== Nodes without a common directory ===
168
169
-image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "blkverify": false, "rewrite-corrupted": false, "vote-threshold": 1}}
170
+image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "vote-threshold": 1}}
171
file format: IMGFMT
172
virtual size: 64M (67108864 bytes)
173
backing file: t.IMGFMT.base (cannot determine actual path)
174
diff --git a/tests/qemu-iotests/228 b/tests/qemu-iotests/228
175
index XXXXXXX..XXXXXXX 100755
176
--- a/tests/qemu-iotests/228
177
+++ b/tests/qemu-iotests/228
178
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \
179
overlay='node0')
180
181
# This should give us the original plain result
182
- # FIXME: Currently, the block layer considers the runtime backing
183
- # file to be different from the image header, which is
184
- # wrong. This is fixed by a future patch.
185
+ # FIXME: Currently, it yields a json:{} filename even though it
186
+ # only contains a @driver and a @file entry, so a plain
187
+ # filename would obviously suffice. This is fixed by a
188
+ # future patch.
189
190
log_node_info(vm.node_info('node0'))
191
192
diff --git a/tests/qemu-iotests/228.out b/tests/qemu-iotests/228.out
193
index XXXXXXX..XXXXXXX 100644
194
--- a/tests/qemu-iotests/228.out
195
+++ b/tests/qemu-iotests/228.out
196
@@ -XXX,XX +XXX,XX @@ bs->backing: (none)
197
{"execute": "blockdev-snapshot", "arguments": {"node": "original-backing", "overlay": "node0"}}
198
{"return": {}}
199
200
-bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
201
+bs->filename: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
202
bs->backing_file: TEST_DIR/PID-base.img
203
bs->backing->bs->filename: TEST_DIR/PID-base.img
204
87
205
--
88
--
206
2.20.1
89
2.13.6
207
90
208
91
diff view generated by jsdifflib
1
Now that bdrv_set_aio_context() works inside drained sections, it can
1
This is in preparation for subtree drains, i.e. drained sections that
2
also use the real drain function instead of open coding something
2
affect not only a single node, but recursively all child nodes, too.
3
similar.
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.
4
16
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
18
---
7
block.c | 15 ++++++---------
19
include/block/block.h | 4 ++--
8
1 file changed, 6 insertions(+), 9 deletions(-)
20
block.c | 13 +++++++++----
9
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:
10
diff --git a/block.c b/block.c
46
diff --git a/block.c b/block.c
11
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
12
--- a/block.c
48
--- a/block.c
13
+++ b/block.c
49
+++ b/block.c
14
@@ -XXX,XX +XXX,XX @@ void bdrv_attach_aio_context(BlockDriverState *bs,
50
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
15
bs->walking_aio_notifiers = false;
51
BlockDriverState *new_bs)
16
}
52
{
17
53
BlockDriverState *old_bs = child->bs;
18
+/* The caller must own the AioContext lock for the old AioContext of bs, but it
54
+ int i;
19
+ * must not own the AioContext lock for new_context (unless new_context is
55
20
+ * the same as the current context of bs). */
56
if (old_bs && new_bs) {
21
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
57
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
22
{
58
}
23
- AioContext *ctx = bdrv_get_aio_context(bs);
59
if (old_bs) {
24
-
60
if (old_bs->quiesce_counter && child->role->drained_end) {
25
- if (ctx == new_context) {
61
- child->role->drained_end(child);
26
+ if (bdrv_get_aio_context(bs) == new_context) {
62
+ for (i = 0; i < old_bs->quiesce_counter; i++) {
27
return;
63
+ child->role->drained_end(child);
28
}
64
+ }
29
65
}
30
- aio_disable_external(ctx);
66
if (child->role->detach) {
31
- bdrv_parent_drained_begin(bs, NULL, false);
67
child->role->detach(child);
32
- bdrv_drain(bs); /* ensure there are no in-flight requests */
68
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
33
-
69
if (new_bs) {
34
+ bdrv_drained_begin(bs);
70
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
35
bdrv_detach_aio_context(bs);
71
if (new_bs->quiesce_counter && child->role->drained_begin) {
36
72
- child->role->drained_begin(child);
37
/* This function executes in the old AioContext so acquire the new one in
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)) {
38
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
88
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
39
*/
89
*/
40
aio_context_acquire(new_context);
90
aio_context_acquire(new_context);
41
bdrv_attach_aio_context(bs, new_context);
91
bdrv_attach_aio_context(bs, new_context);
42
- bdrv_parent_drained_end(bs, NULL, false);
92
- bdrv_parent_drained_end(bs);
43
- aio_enable_external(ctx);
93
+ bdrv_parent_drained_end(bs, NULL);
44
+ bdrv_drained_end(bs);
94
aio_enable_external(ctx);
45
aio_context_release(new_context);
95
aio_context_release(new_context);
46
}
96
}
47
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
}
48
--
256
--
49
2.20.1
257
2.13.6
50
258
51
259
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
bdrv_drained_begin() waits for the completion of requests in the whole
2
subtree, but it only actually keeps its immediate bs parameter quiesced
3
until bdrv_drained_end().
2
4
3
Make bdrv_get_full_backing_filename_from_filename() return an allocated
5
Add a version that keeps the whole subtree drained. As of this commit,
4
string instead of placing the result in a caller-provided buffer.
6
graph changes cannot be allowed during a subtree drained section, but
7
this will be fixed soon.
5
8
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Message-id: 20190201192935.18394-11-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
---
10
include/block/block.h | 7 +++---
11
include/block/block.h | 13 +++++++++++++
11
block.c | 53 ++++++++++++++++++++++++++++++-------------
12
block/io.c | 54 ++++++++++++++++++++++++++++++++++++++++-----------
12
block/vmdk.c | 10 ++++----
13
2 files changed, 56 insertions(+), 11 deletions(-)
13
qemu-img.c | 12 ++++------
14
4 files changed, 49 insertions(+), 33 deletions(-)
15
14
16
diff --git a/include/block/block.h b/include/block/block.h
15
diff --git a/include/block/block.h b/include/block/block.h
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/block.h
17
--- a/include/block/block.h
19
+++ b/include/block/block.h
18
+++ b/include/block/block.h
20
@@ -XXX,XX +XXX,XX @@ void bdrv_get_backing_filename(BlockDriverState *bs,
19
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
21
char *filename, int filename_size);
20
void bdrv_drained_begin(BlockDriverState *bs);
22
void bdrv_get_full_backing_filename(BlockDriverState *bs,
21
23
char *dest, size_t sz, Error **errp);
22
/**
24
-void bdrv_get_full_backing_filename_from_filename(const char *backed,
23
+ * Like bdrv_drained_begin, but recursively begins a quiesced section for
25
- const char *backing,
24
+ * exclusive access to all child nodes as well.
26
- char *dest, size_t sz,
25
+ *
27
- Error **errp);
26
+ * Graph changes are not allowed during a subtree drain section.
28
+char *bdrv_get_full_backing_filename_from_filename(const char *backed,
27
+ */
29
+ const char *backing,
28
+void bdrv_subtree_drained_begin(BlockDriverState *bs);
30
+ Error **errp);
29
+
31
30
+/**
32
int path_has_protocol(const char *path);
31
* bdrv_drained_end:
33
int path_is_absolute(const char *path);
32
*
34
diff --git a/block.c b/block.c
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
35
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
36
--- a/block.c
47
--- a/block/io.c
37
+++ b/block.c
48
+++ b/block/io.c
38
@@ -XXX,XX +XXX,XX @@ fail:
49
@@ -XXX,XX +XXX,XX @@ typedef struct {
39
return -EACCES;
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;
40
}
59
}
41
60
42
-void bdrv_get_full_backing_filename_from_filename(const char *backed,
61
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
43
- const char *backing,
62
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
44
- char *dest, size_t sz,
63
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
45
- Error **errp)
64
+ BdrvChild *parent);
46
+/*
65
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
47
+ * If @backing is empty, this function returns NULL without setting
66
+ BdrvChild *parent);
48
+ * @errp. In all other cases, NULL will only be returned with @errp
67
49
+ * set.
68
static void bdrv_co_drain_bh_cb(void *opaque)
50
+ *
51
+ * Therefore, a return value of NULL without @errp set means that
52
+ * there is no backing file; if @errp is set, there is one but its
53
+ * absolute filename cannot be generated.
54
+ */
55
+char *bdrv_get_full_backing_filename_from_filename(const char *backed,
56
+ const char *backing,
57
+ Error **errp)
58
{
69
{
59
- if (backing[0] == '\0' || path_has_protocol(backing) ||
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
60
- path_is_absolute(backing))
71
61
- {
72
bdrv_dec_in_flight(bs);
62
- pstrcpy(dest, sz, backing);
73
if (data->begin) {
63
+ if (backing[0] == '\0') {
74
- bdrv_do_drained_begin(bs, data->parent);
64
+ return NULL;
75
+ bdrv_do_drained_begin(bs, data->recursive, data->parent);
65
+ } else if (path_has_protocol(backing) || path_is_absolute(backing)) {
66
+ return g_strdup(backing);
67
} else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) {
68
error_setg(errp, "Cannot use relative backing file names for '%s'",
69
backed);
70
+ return NULL;
71
} else {
76
} else {
72
- path_combine_deprecated(dest, sz, backed, backing);
77
- bdrv_do_drained_end(bs, data->parent);
73
+ return path_combine(backed, backing);
78
+ bdrv_do_drained_end(bs, data->recursive, data->parent);
74
}
79
}
80
81
data->done = true;
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
75
}
83
}
76
84
77
@@ -XXX,XX +XXX,XX @@ void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
85
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
78
Error **errp)
86
- bool begin, BdrvChild *parent)
87
+ bool begin, bool recursive,
88
+ BdrvChild *parent)
79
{
89
{
80
char *backed;
90
BdrvCoDrainData data;
81
+ char *full_name;
91
82
+ Error *local_error = NULL;
92
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
83
93
.bs = bs,
84
bdrv_refresh_filename(bs);
94
.done = false,
85
95
.begin = begin,
86
backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
96
+ .recursive = recursive,
87
- bdrv_get_full_backing_filename_from_filename(backed, bs->backing_file,
97
.parent = parent,
88
- dest, sz, errp);
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;
89
+
109
+
90
+ full_name = bdrv_get_full_backing_filename_from_filename(backed,
110
if (qemu_in_coroutine()) {
91
+ bs->backing_file,
111
- bdrv_co_yield_to_drain(bs, true, parent);
92
+ &local_error);
112
+ bdrv_co_yield_to_drain(bs, true, recursive, parent);
93
+ if (full_name) {
113
return;
94
+ pstrcpy(dest, sz, full_name);
114
}
95
+ g_free(full_name);
115
96
+ } else if (local_error) {
116
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
97
+ error_propagate(errp, local_error);
117
bdrv_parent_drained_begin(bs, parent);
98
+ } else if (sz > 0) {
118
bdrv_drain_invoke(bs, true, false);
99
+ *dest = '\0';
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
+ }
100
+ }
125
+ }
101
}
126
}
102
127
103
void bdrv_register(BlockDriver *bdrv)
128
void bdrv_drained_begin(BlockDriverState *bs)
104
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
129
{
105
size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, img_size);
130
- bdrv_do_drained_begin(bs, NULL);
106
if (backing_file && !(flags & BDRV_O_NO_BACKING)) {
131
+ bdrv_do_drained_begin(bs, false, NULL);
107
BlockDriverState *bs;
132
+}
108
- char *full_backing = g_new0(char, PATH_MAX);
133
+
109
+ char *full_backing;
134
+void bdrv_subtree_drained_begin(BlockDriverState *bs)
110
int back_flags;
135
+{
111
QDict *backing_options = NULL;
136
+ bdrv_do_drained_begin(bs, true, NULL);
112
137
}
113
- bdrv_get_full_backing_filename_from_filename(filename, backing_file,
138
114
- full_backing, PATH_MAX,
139
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
115
- &local_err);
140
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
116
+ full_backing =
141
+ BdrvChild *parent)
117
+ bdrv_get_full_backing_filename_from_filename(filename, backing_file,
142
{
118
+ &local_err);
143
+ BdrvChild *child, *next;
119
if (local_err) {
144
int old_quiesce_counter;
120
- g_free(full_backing);
145
121
goto out;
146
if (qemu_in_coroutine()) {
122
}
147
- bdrv_co_yield_to_drain(bs, false, parent);
123
+ assert(full_backing);
148
+ bdrv_co_yield_to_drain(bs, false, recursive, parent);
124
149
return;
125
/* backing files always opened read-only */
150
}
126
back_flags = flags;
151
assert(bs->quiesce_counter > 0);
127
diff --git a/block/vmdk.c b/block/vmdk.c
152
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
128
index XXXXXXX..XXXXXXX 100644
153
if (old_quiesce_counter == 1) {
129
--- a/block/vmdk.c
154
aio_enable_external(bdrv_get_aio_context(bs));
130
+++ b/block/vmdk.c
155
}
131
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
156
+
132
157
+ if (recursive) {
133
if (backing_file) {
158
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
134
BlockBackend *backing;
159
+ bdrv_do_drained_end(child->bs, true, child);
135
- char *full_backing = g_new0(char, PATH_MAX);
160
+ }
136
- bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, backing_file,
161
+ }
137
- full_backing, PATH_MAX,
162
}
138
- &local_err);
163
139
+ char *full_backing =
164
void bdrv_drained_end(BlockDriverState *bs)
140
+ bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename,
165
{
141
+ backing_file,
166
- bdrv_do_drained_end(bs, NULL);
142
+ &local_err);
167
+ bdrv_do_drained_end(bs, false, NULL);
143
if (local_err) {
168
+}
144
- g_free(full_backing);
169
+
145
error_propagate(errp, local_err);
170
+void bdrv_subtree_drained_end(BlockDriverState *bs)
146
ret = -ENOENT;
171
+{
147
goto exit;
172
+ bdrv_do_drained_end(bs, true, NULL);
148
}
173
}
149
+ assert(full_backing);
174
150
175
/*
151
backing = blk_new_open(full_backing, NULL, NULL,
152
BDRV_O_NO_BACKING, errp);
153
diff --git a/qemu-img.c b/qemu-img.c
154
index XXXXXXX..XXXXXXX 100644
155
--- a/qemu-img.c
156
+++ b/qemu-img.c
157
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
158
bdrv_refresh_filename(bs);
159
overlay_filename = bs->exact_filename[0] ? bs->exact_filename
160
: bs->filename;
161
- out_real_path = g_malloc(PATH_MAX);
162
-
163
- bdrv_get_full_backing_filename_from_filename(overlay_filename,
164
- out_baseimg,
165
- out_real_path,
166
- PATH_MAX,
167
- &local_err);
168
+ out_real_path =
169
+ bdrv_get_full_backing_filename_from_filename(overlay_filename,
170
+ out_baseimg,
171
+ &local_err);
172
if (local_err) {
173
error_reportf_err(local_err,
174
"Could not resolve backing filename: ");
175
ret = -1;
176
- g_free(out_real_path);
177
goto out;
178
}
179
180
--
176
--
181
2.20.1
177
2.13.6
182
178
183
179
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Add a subtree drain version to the existing test cases.
2
2
3
This is a general function for making a filename that is relative to a
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
certain BDS absolute.
4
---
5
tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++-
6
1 file changed, 26 insertions(+), 1 deletion(-)
5
7
6
It calls bdrv_get_full_backing_filename_from_filename() for now, but
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
7
that will be changed in a follow-up patch.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Message-id: 20190201192935.18394-13-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block.c | 27 ++++++++++++++++++++-------
15
1 file changed, 20 insertions(+), 7 deletions(-)
16
17
diff --git a/block.c b/block.c
18
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
19
--- a/block.c
10
--- a/tests/test-bdrv-drain.c
20
+++ b/block.c
11
+++ b/tests/test-bdrv-drain.c
21
@@ -XXX,XX +XXX,XX @@ char *bdrv_get_full_backing_filename_from_filename(const char *backed,
12
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
13
enum drain_type {
14
BDRV_DRAIN_ALL,
15
BDRV_DRAIN,
16
+ BDRV_SUBTREE_DRAIN,
17
DRAIN_TYPE_MAX,
18
};
19
20
@@ -XXX,XX +XXX,XX @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
21
switch (drain_type) {
22
case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
23
case BDRV_DRAIN: bdrv_drained_begin(bs); break;
24
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break;
25
default: g_assert_not_reached();
22
}
26
}
23
}
27
}
24
28
@@ -XXX,XX +XXX,XX @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
25
-char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp)
29
switch (drain_type) {
26
+/*
30
case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
27
+ * If @filename is empty or NULL, this function returns NULL without
31
case BDRV_DRAIN: bdrv_drained_end(bs); break;
28
+ * setting @errp. In all other cases, NULL will only be returned with
32
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break;
29
+ * @errp set.
33
default: g_assert_not_reached();
30
+ */
34
}
31
+static char *bdrv_make_absolute_filename(BlockDriverState *relative_to,
35
}
32
+ const char *filename, Error **errp)
36
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
33
{
37
test_drv_cb_common(BDRV_DRAIN, false);
34
- char *backed;
38
}
35
+ char *bs_filename;
39
36
40
+static void test_drv_cb_drain_subtree(void)
37
- bdrv_refresh_filename(bs);
41
+{
38
+ bdrv_refresh_filename(relative_to);
42
+ test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
39
+
40
+ bs_filename = relative_to->exact_filename[0]
41
+ ? relative_to->exact_filename
42
+ : relative_to->filename;
43
44
- backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
45
- return bdrv_get_full_backing_filename_from_filename(backed,
46
- bs->backing_file,
47
- errp);
48
+ return bdrv_get_full_backing_filename_from_filename(bs_filename,
49
+ filename ?: "", errp);
50
+}
43
+}
51
+
44
+
52
+char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp)
45
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
46
{
47
BlockBackend *blk;
48
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
49
test_quiesce_common(BDRV_DRAIN, false);
50
}
51
52
+static void test_quiesce_drain_subtree(void)
53
+{
53
+{
54
+ return bdrv_make_absolute_filename(bs, bs->backing_file, errp);
54
+ test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
55
+}
56
+
57
static void test_nested(void)
58
{
59
BlockBackend *blk;
60
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
61
/* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
62
int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
63
(inner != BDRV_DRAIN_ALL);
64
- int backing_quiesce = 0;
65
+ int backing_quiesce = (outer == BDRV_SUBTREE_DRAIN) +
66
+ (inner == BDRV_SUBTREE_DRAIN);
67
int backing_cb_cnt = (outer != BDRV_DRAIN) +
68
(inner != BDRV_DRAIN);
69
70
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_drain(void)
71
test_blockjob_common(BDRV_DRAIN);
55
}
72
}
56
73
57
void bdrv_register(BlockDriver *bdrv)
74
+static void test_blockjob_drain_subtree(void)
75
+{
76
+ test_blockjob_common(BDRV_SUBTREE_DRAIN);
77
+}
78
+
79
int main(int argc, char **argv)
80
{
81
bdrv_init();
82
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
83
84
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
85
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
86
+ g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
87
+ test_drv_cb_drain_subtree);
88
89
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
90
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
91
+ g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
92
+ test_quiesce_drain_subtree);
93
94
g_test_add_func("/bdrv-drain/nested", test_nested);
95
96
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
97
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
98
+ g_test_add_func("/bdrv-drain/blockjob/drain_subtree",
99
+ test_blockjob_drain_subtree);
100
101
return g_test_run();
102
}
58
--
103
--
59
2.20.1
104
2.13.6
60
105
61
106
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
If bdrv_do_drained_begin/end() are called in coroutine context, they
2
first use a BH to get out of the coroutine context. Call some existing
3
tests again from a coroutine to cover this code path.
2
4
3
Besides being safe for arbitrary path lengths, after some follow-up
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
patches all callers will want a freshly allocated buffer anyway.
6
---
7
tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 59 insertions(+)
5
9
6
In the meantime, path_combine_deprecated() is added which has the same
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
7
interface as path_combine() had before this patch. All callers to that
8
function will be converted in follow-up patches.
9
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Message-id: 20190201192935.18394-10-mreitz@redhat.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
include/block/block.h | 4 +-
17
block.c | 85 ++++++++++++++++++++++++-------------------
18
block/vmdk.c | 3 +-
19
3 files changed, 49 insertions(+), 43 deletions(-)
20
21
diff --git a/include/block/block.h b/include/block/block.h
22
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
23
--- a/include/block/block.h
12
--- a/tests/test-bdrv-drain.c
24
+++ b/include/block/block.h
13
+++ b/tests/test-bdrv-drain.c
25
@@ -XXX,XX +XXX,XX @@ void bdrv_get_full_backing_filename_from_filename(const char *backed,
14
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
26
15
*aio_ret = ret;
27
int path_has_protocol(const char *path);
28
int path_is_absolute(const char *path);
29
-void path_combine(char *dest, int dest_size,
30
- const char *base_path,
31
- const char *filename);
32
+char *path_combine(const char *base_path, const char *filename);
33
34
int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
35
int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
36
diff --git a/block.c b/block.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block.c
39
+++ b/block.c
40
@@ -XXX,XX +XXX,XX @@ int path_is_absolute(const char *path)
41
#endif
42
}
16
}
43
17
44
-/* if filename is absolute, just copy it to dest. Otherwise, build a
18
+typedef struct CallInCoroutineData {
45
+/* if filename is absolute, just return its duplicate. Otherwise, build a
19
+ void (*entry)(void);
46
path to it by considering it is relative to base_path. URL are
20
+ bool done;
47
supported. */
21
+} CallInCoroutineData;
48
-void path_combine(char *dest, int dest_size,
49
- const char *base_path,
50
- const char *filename)
51
+char *path_combine(const char *base_path, const char *filename)
52
{
53
+ const char *protocol_stripped = NULL;
54
const char *p, *p1;
55
+ char *result;
56
int len;
57
58
- if (dest_size <= 0)
59
- return;
60
if (path_is_absolute(filename)) {
61
- pstrcpy(dest, dest_size, filename);
62
- } else {
63
- const char *protocol_stripped = NULL;
64
+ return g_strdup(filename);
65
+ }
66
67
- if (path_has_protocol(base_path)) {
68
- protocol_stripped = strchr(base_path, ':');
69
- if (protocol_stripped) {
70
- protocol_stripped++;
71
- }
72
+ if (path_has_protocol(base_path)) {
73
+ protocol_stripped = strchr(base_path, ':');
74
+ if (protocol_stripped) {
75
+ protocol_stripped++;
76
}
77
- p = protocol_stripped ?: base_path;
78
+ }
79
+ p = protocol_stripped ?: base_path;
80
81
- p1 = strrchr(base_path, '/');
82
+ p1 = strrchr(base_path, '/');
83
#ifdef _WIN32
84
- {
85
- const char *p2;
86
- p2 = strrchr(base_path, '\\');
87
- if (!p1 || p2 > p1)
88
- p1 = p2;
89
+ {
90
+ const char *p2;
91
+ p2 = strrchr(base_path, '\\');
92
+ if (!p1 || p2 > p1) {
93
+ p1 = p2;
94
}
95
+ }
96
#endif
97
- if (p1)
98
- p1++;
99
- else
100
- p1 = base_path;
101
- if (p1 > p)
102
- p = p1;
103
- len = p - base_path;
104
- if (len > dest_size - 1)
105
- len = dest_size - 1;
106
- memcpy(dest, base_path, len);
107
- dest[len] = '\0';
108
- pstrcat(dest, dest_size, filename);
109
+ if (p1) {
110
+ p1++;
111
+ } else {
112
+ p1 = base_path;
113
+ }
114
+ if (p1 > p) {
115
+ p = p1;
116
}
117
+ len = p - base_path;
118
+
22
+
119
+ result = g_malloc(len + strlen(filename) + 1);
23
+static coroutine_fn void call_in_coroutine_entry(void *opaque)
120
+ memcpy(result, base_path, len);
24
+{
121
+ strcpy(result + len, filename);
25
+ CallInCoroutineData *data = opaque;
122
+
26
+
123
+ return result;
27
+ data->entry();
28
+ data->done = true;
124
+}
29
+}
125
+
30
+
126
+static void path_combine_deprecated(char *dest, int dest_size,
31
+static void call_in_coroutine(void (*entry)(void))
127
+ const char *base_path,
128
+ const char *filename)
129
+{
32
+{
130
+ char *combined = path_combine(base_path, filename);
33
+ Coroutine *co;
131
+ pstrcpy(dest, dest_size, combined);
34
+ CallInCoroutineData data = {
132
+ g_free(combined);
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);
133
}
51
}
134
52
135
/*
53
+static void test_drv_cb_co_drain(void)
136
@@ -XXX,XX +XXX,XX @@ void bdrv_get_full_backing_filename_from_filename(const char *backed,
54
+{
137
error_setg(errp, "Cannot use relative backing file names for '%s'",
55
+ call_in_coroutine(test_drv_cb_drain);
138
backed);
56
+}
139
} else {
57
+
140
- path_combine(dest, sz, backed, backing);
58
+static void test_drv_cb_co_drain_subtree(void)
141
+ path_combine_deprecated(dest, sz, backed, backing);
59
+{
142
}
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);
143
}
68
}
144
69
145
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
70
+static void test_quiesce_co_drain(void)
146
} else {
71
+{
147
/* If not an absolute filename path, make it relative to the current
72
+ call_in_coroutine(test_quiesce_drain);
148
* image's filename path */
73
+}
149
- path_combine(filename_tmp, PATH_MAX, curr_bs->filename,
74
+
150
- backing_file);
75
+static void test_quiesce_co_drain_subtree(void)
151
+ path_combine_deprecated(filename_tmp, PATH_MAX, curr_bs->filename,
76
+{
152
+ backing_file);
77
+ call_in_coroutine(test_quiesce_drain_subtree);
153
78
+}
154
/* We are going to compare absolute pathnames */
79
+
155
if (!realpath(filename_tmp, filename_full)) {
80
static void test_nested(void)
156
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
81
{
157
82
BlockBackend *blk;
158
/* We need to make sure the backing filename we are comparing against
83
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
159
* is relative to the current image filename (or absolute) */
84
g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
160
- path_combine(filename_tmp, PATH_MAX, curr_bs->filename,
85
test_drv_cb_drain_subtree);
161
- curr_bs->backing_file);
86
162
+ path_combine_deprecated(filename_tmp, PATH_MAX, curr_bs->filename,
87
+ // XXX bdrv_drain_all() doesn't work in coroutine context
163
+ curr_bs->backing_file);
88
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain);
164
89
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree",
165
if (!realpath(filename_tmp, backing_file_full)) {
90
+ test_drv_cb_co_drain_subtree);
166
continue;
91
+
167
diff --git a/block/vmdk.c b/block/vmdk.c
92
+
168
index XXXXXXX..XXXXXXX 100644
93
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
169
--- a/block/vmdk.c
94
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
170
+++ b/block/vmdk.c
95
g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
171
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
96
test_quiesce_drain_subtree);
172
return -EINVAL;
97
173
}
98
+ // XXX bdrv_drain_all() doesn't work in coroutine context
174
99
+ g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain);
175
- extent_path = g_malloc0(PATH_MAX);
100
+ g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree",
176
- path_combine(extent_path, PATH_MAX, desc_file_path, fname);
101
+ test_quiesce_co_drain_subtree);
177
+ extent_path = path_combine(desc_file_path, fname);
102
+
178
103
g_test_add_func("/bdrv-drain/nested", test_nested);
179
ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
104
180
assert(ret < 32);
105
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
181
--
106
--
182
2.20.1
107
2.13.6
183
108
184
109
diff view generated by jsdifflib
1
bdrv_drain() must not leave connection_co scheduled, so bs->in_flight
1
Test that drain sections are correctly propagated through the graph.
2
needs to be increased while the coroutine is waiting to be scheduled
3
in the new AioContext after nbd_client_attach_aio_context().
4
2
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
4
---
7
block/nbd-client.c | 20 ++++++++++++++++++--
5
tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 18 insertions(+), 2 deletions(-)
6
1 file changed, 74 insertions(+)
9
7
10
diff --git a/block/nbd-client.c b/block/nbd-client.c
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
11
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
12
--- a/block/nbd-client.c
10
--- a/tests/test-bdrv-drain.c
13
+++ b/block/nbd-client.c
11
+++ b/tests/test-bdrv-drain.c
14
@@ -XXX,XX +XXX,XX @@ void nbd_client_detach_aio_context(BlockDriverState *bs)
12
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
15
qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc));
13
blk_unref(blk);
16
}
14
}
17
15
18
+static void nbd_client_attach_aio_context_bh(void *opaque)
16
+static void test_multiparent(void)
19
+{
17
+{
20
+ BlockDriverState *bs = opaque;
18
+ BlockBackend *blk_a, *blk_b;
21
+ NBDClientSession *client = nbd_get_client_session(bs);
19
+ BlockDriverState *bs_a, *bs_b, *backing;
20
+ BDRVTestState *a_s, *b_s, *backing_s;
22
+
21
+
23
+ /* The node is still drained, so we know the coroutine has yielded in
22
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
24
+ * nbd_read_eof(), the only place where bs->in_flight can reach 0, or it is
23
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
25
+ * entered for the first time. Both places are safe for entering the
24
+ &error_abort);
26
+ * coroutine.*/
25
+ a_s = bs_a->opaque;
27
+ qemu_aio_coroutine_enter(bs->aio_context, client->connection_co);
26
+ blk_insert_bs(blk_a, bs_a, &error_abort);
28
+ bdrv_dec_in_flight(bs);
27
+
28
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
29
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
30
+ &error_abort);
31
+ b_s = bs_b->opaque;
32
+ blk_insert_bs(blk_b, bs_b, &error_abort);
33
+
34
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
35
+ backing_s = backing->opaque;
36
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
37
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
38
+
39
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
40
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
41
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(a_s->drain_count, ==, 0);
43
+ g_assert_cmpint(b_s->drain_count, ==, 0);
44
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
45
+
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
47
+
48
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
49
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
50
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
51
+ g_assert_cmpint(a_s->drain_count, ==, 1);
52
+ g_assert_cmpint(b_s->drain_count, ==, 1);
53
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
54
+
55
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
56
+
57
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 2);
58
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
59
+ g_assert_cmpint(backing->quiesce_counter, ==, 2);
60
+ g_assert_cmpint(a_s->drain_count, ==, 2);
61
+ g_assert_cmpint(b_s->drain_count, ==, 2);
62
+ g_assert_cmpint(backing_s->drain_count, ==, 2);
63
+
64
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
65
+
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
69
+ g_assert_cmpint(a_s->drain_count, ==, 1);
70
+ g_assert_cmpint(b_s->drain_count, ==, 1);
71
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
72
+
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
74
+
75
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
76
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
77
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
78
+ g_assert_cmpint(a_s->drain_count, ==, 0);
79
+ g_assert_cmpint(b_s->drain_count, ==, 0);
80
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
81
+
82
+ bdrv_unref(backing);
83
+ bdrv_unref(bs_a);
84
+ bdrv_unref(bs_b);
85
+ blk_unref(blk_a);
86
+ blk_unref(blk_b);
29
+}
87
+}
30
+
88
+
31
void nbd_client_attach_aio_context(BlockDriverState *bs,
89
32
AioContext *new_context)
90
typedef struct TestBlockJob {
33
{
91
BlockJob common;
34
NBDClientSession *client = nbd_get_client_session(bs);
92
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
35
qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc), new_context);
93
test_quiesce_co_drain_subtree);
36
94
37
- /* FIXME Really need a bdrv_inc_in_flight() here */
95
g_test_add_func("/bdrv-drain/nested", test_nested);
38
- aio_co_schedule(new_context, client->connection_co);
96
+ g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
39
+ bdrv_inc_in_flight(bs);
97
40
+
98
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
41
+ /* Need to wait here for the BH to run because the BH must run while the
99
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
42
+ * node is still drained. */
43
+ aio_wait_bh_oneshot(new_context, nbd_client_attach_aio_context_bh, bs);
44
}
45
46
void nbd_client_close(BlockDriverState *bs)
47
--
100
--
48
2.20.1
101
2.13.6
49
102
50
103
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
We need to remember how many of the drain sections in which a node is
2
2
were recursive (i.e. subtree drain rather than node drain), so that they
3
This function may be implemented by block drivers to derive a directory
3
can be correctly applied when children are added or removed during the
4
name from a BDS. Concatenating this g_free()-able string with a relative
4
drained section.
5
filename must result in a valid (not necessarily existing) filename, so
5
6
this is a function that should generally be not implemented by format
6
With this change, it is safe to modify the graph even inside a
7
drivers, because this is protocol-specific.
7
bdrv_subtree_drained_begin/end() section.
8
8
9
If a BDS's driver does not implement this function, bdrv_dirname() will
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
fall through to the BDS's file if it exists. If it does not, the
11
exact_filename field will be used to generate a directory name.
12
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Alberto Garcia <berto@igalia.com>
15
Message-id: 20190201192935.18394-15-mreitz@redhat.com
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
10
---
18
include/block/block.h | 1 +
11
include/block/block.h | 2 --
19
include/block/block_int.h | 7 +++++++
12
include/block/block_int.h | 5 +++++
20
block.c | 27 +++++++++++++++++++++++++++
13
block.c | 32 +++++++++++++++++++++++++++++---
21
3 files changed, 35 insertions(+)
14
block/io.c | 28 ++++++++++++++++++++++++----
15
4 files changed, 58 insertions(+), 9 deletions(-)
22
16
23
diff --git a/include/block/block.h b/include/block/block.h
17
diff --git a/include/block/block.h b/include/block/block.h
24
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
25
--- a/include/block/block.h
19
--- a/include/block/block.h
26
+++ b/include/block/block.h
20
+++ b/include/block/block.h
27
@@ -XXX,XX +XXX,XX @@ char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp);
21
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs);
28
char *bdrv_get_full_backing_filename_from_filename(const char *backed,
22
/**
29
const char *backing,
23
* Like bdrv_drained_begin, but recursively begins a quiesced section for
30
Error **errp);
24
* exclusive access to all child nodes as well.
31
+char *bdrv_dirname(BlockDriverState *bs, Error **errp);
25
- *
32
26
- * Graph changes are not allowed during a subtree drain section.
33
int path_has_protocol(const char *path);
27
*/
34
int path_is_absolute(const char *path);
28
void bdrv_subtree_drained_begin(BlockDriverState *bs);
29
35
diff --git a/include/block/block_int.h b/include/block/block_int.h
30
diff --git a/include/block/block_int.h b/include/block/block_int.h
36
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
37
--- a/include/block/block_int.h
32
--- a/include/block/block_int.h
38
+++ b/include/block/block_int.h
33
+++ b/include/block/block_int.h
39
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
34
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
40
35
41
void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
36
/* Accessed with atomic ops. */
42
37
int quiesce_counter;
43
+ /*
38
+ int recursive_quiesce_counter;
44
+ * Returns an allocated string which is the directory name of this BDS: It
39
+
45
+ * will be used to make relative filenames absolute by prepending this
40
unsigned int write_gen; /* Current data generation */
46
+ * function's return value to them.
41
47
+ */
42
/* Protected by reqs_lock. */
48
+ char *(*bdrv_dirname)(BlockDriverState *bs, Error **errp);
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
49
+
44
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
50
/* aio */
45
BdrvRequestFlags flags);
51
BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs,
46
52
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags,
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
53
diff --git a/block.c b/block.c
54
index XXXXXXX..XXXXXXX 100644
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block.c
55
--- a/block.c
56
+++ b/block.c
56
+++ b/block.c
57
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
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));
58
}
114
}
59
}
115
if (old_bs) {
60
116
+ /* Detach first so that the recursive drain sections coming from @child
61
+char *bdrv_dirname(BlockDriverState *bs, Error **errp)
117
+ * are already gone and we only end the drain sections that came from
62
+{
118
+ * elsewhere. */
63
+ BlockDriver *drv = bs->drv;
119
+ if (child->role->detach) {
64
+
120
+ child->role->detach(child);
65
+ if (!drv) {
121
+ }
66
+ error_setg(errp, "Node '%s' is ejected", bs->node_name);
122
if (old_bs->quiesce_counter && child->role->drained_end) {
67
+ return NULL;
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);
68
+ }
195
+ }
69
+
196
+}
70
+ if (drv->bdrv_dirname) {
197
+
71
+ return drv->bdrv_dirname(bs, errp);
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);
72
+ }
204
+ }
73
+
74
+ if (bs->file) {
75
+ return bdrv_dirname(bs->file->bs, errp);
76
+ }
77
+
78
+ bdrv_refresh_filename(bs);
79
+ if (bs->exact_filename[0] != '\0') {
80
+ return path_combine(bs->exact_filename, "");
81
+ }
82
+
83
+ error_setg(errp, "Cannot generate a base directory for %s nodes",
84
+ drv->format_name);
85
+ return NULL;
86
+}
205
+}
87
+
206
+
88
/*
207
/*
89
* Hot add/remove a BDS's child. So the user can take a child offline when
208
* Wait for pending requests to complete on a single BlockDriverState subtree,
90
* it is broken and take a new child online
209
* and suspend block driver's internal I/O until next request arrives.
91
--
210
--
92
2.20.1
211
2.13.6
93
212
94
213
diff view generated by jsdifflib
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
---
2
---
4
tests/test-bdrv-drain.c | 32 ++++++++++++++++++++++++++++++++
3
tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
5
1 file changed, 32 insertions(+)
4
1 file changed, 80 insertions(+)
6
5
7
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
8
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
9
--- a/tests/test-bdrv-drain.c
8
--- a/tests/test-bdrv-drain.c
10
+++ b/tests/test-bdrv-drain.c
9
+++ b/tests/test-bdrv-drain.c
11
@@ -XXX,XX +XXX,XX @@ static void test_append_to_drained(void)
10
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
12
blk_unref(blk);
11
blk_unref(blk_b);
13
}
12
}
14
13
15
+static void test_set_aio_context(void)
14
+static void test_graph_change(void)
16
+{
15
+{
17
+ BlockDriverState *bs;
16
+ BlockBackend *blk_a, *blk_b;
18
+ IOThread *a = iothread_new();
17
+ BlockDriverState *bs_a, *bs_b, *backing;
19
+ IOThread *b = iothread_new();
18
+ BDRVTestState *a_s, *b_s, *backing_s;
20
+ AioContext *ctx_a = iothread_get_aio_context(a);
21
+ AioContext *ctx_b = iothread_get_aio_context(b);
22
+
19
+
23
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
20
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
24
+ &error_abort);
21
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
22
+ &error_abort);
23
+ a_s = bs_a->opaque;
24
+ blk_insert_bs(blk_a, bs_a, &error_abort);
25
+
25
+
26
+ bdrv_drained_begin(bs);
26
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
27
+ bdrv_set_aio_context(bs, ctx_a);
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);
28
+
31
+
29
+ aio_context_acquire(ctx_a);
32
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
30
+ bdrv_drained_end(bs);
33
+ backing_s = backing->opaque;
34
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
31
+
35
+
32
+ bdrv_drained_begin(bs);
36
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
33
+ bdrv_set_aio_context(bs, ctx_b);
37
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
34
+ aio_context_release(ctx_a);
38
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
35
+ aio_context_acquire(ctx_b);
39
+ g_assert_cmpint(a_s->drain_count, ==, 0);
36
+ bdrv_set_aio_context(bs, qemu_get_aio_context());
40
+ g_assert_cmpint(b_s->drain_count, ==, 0);
37
+ aio_context_release(ctx_b);
41
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
38
+ bdrv_drained_end(bs);
39
+
42
+
40
+ bdrv_unref(bs);
43
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
41
+ iothread_join(a);
44
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
42
+ iothread_join(b);
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);
43
+}
91
+}
44
+
92
+
45
int main(int argc, char **argv)
93
46
{
94
typedef struct TestBlockJob {
47
int ret;
95
BlockJob common;
48
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
96
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
49
97
50
g_test_add_func("/bdrv-drain/attach/drain", test_append_to_drained);
98
g_test_add_func("/bdrv-drain/nested", test_nested);
51
99
g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
52
+ g_test_add_func("/bdrv-drain/set_aio_context", test_set_aio_context);
100
+ g_test_add_func("/bdrv-drain/graph-change", test_graph_change);
53
+
101
54
ret = g_test_run();
102
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
55
qemu_event_destroy(&done_event);
103
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
56
return ret;
57
--
104
--
58
2.20.1
105
2.13.6
59
106
60
107
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Since commit bde70715, base is the only node that is reopened in
2
commit_start(). This means that the code, which still involves an
3
explicit BlockReopenQueue, can now be simplified by using bdrv_reopen().
2
4
3
If there's an error in commit_start() then the block job must be
4
deleted before replacing commit_top_bs, otherwise it will fail because
5
of lack of permissions. This happens since the permission system was
6
introduced in 8dfba2797761d8a43744e4e6571c8175e448a478.
7
8
Fortunately this bug doesn't seem to be possible to reproduce at the
9
moment without changing the code.
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Fam Zheng <famz@redhat.com>
13
---
7
---
14
block/commit.c | 4 +++-
8
block/commit.c | 8 +-------
15
1 file changed, 3 insertions(+), 1 deletion(-)
9
1 file changed, 1 insertion(+), 7 deletions(-)
16
10
17
diff --git a/block/commit.c b/block/commit.c
11
diff --git a/block/commit.c b/block/commit.c
18
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
19
--- a/block/commit.c
13
--- a/block/commit.c
20
+++ b/block/commit.c
14
+++ b/block/commit.c
21
@@ -XXX,XX +XXX,XX @@ fail:
15
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
22
if (s->top) {
16
const char *filter_node_name, Error **errp)
23
blk_unref(s->top);
17
{
24
}
18
CommitBlockJob *s;
25
+ job_early_fail(&s->common.job);
19
- BlockReopenQueue *reopen_queue = NULL;
26
+ /* commit_top_bs has to be replaced after deleting the block job,
20
int orig_base_flags;
27
+ * otherwise this would fail because of lack of permissions. */
21
BlockDriverState *iter;
28
if (commit_top_bs) {
22
BlockDriverState *commit_top_bs = NULL;
29
bdrv_replace_node(commit_top_bs, top, &error_abort);
23
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
30
}
24
/* convert base to r/w, if necessary */
31
- job_early_fail(&s->common.job);
25
orig_base_flags = bdrv_get_flags(base);
32
}
26
if (!(orig_base_flags & BDRV_O_RDWR)) {
33
27
- reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
34
28
- orig_base_flags | BDRV_O_RDWR);
29
- }
30
-
31
- if (reopen_queue) {
32
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
33
+ bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
34
if (local_err != NULL) {
35
error_propagate(errp, local_err);
36
goto fail;
35
--
37
--
36
2.20.1
38
2.13.6
37
39
38
40
diff view generated by jsdifflib
Deleted patch
1
From: Daniel P. Berrangé <berrange@redhat.com>
2
1
3
Error reporting for user_creatable_add_opts_foreach was changed so that
4
it no longer called 'error_report_err' in:
5
6
commit 7e1e0c11127bde81cff260fc6859690435c509d6
7
Author: Markus Armbruster <armbru@redhat.com>
8
Date: Wed Oct 17 10:26:43 2018 +0200
9
10
qom: Clean up error reporting in user_creatable_add_opts_foreach()
11
12
Some callers were updated to pass in "&error_fatal" but all the ones in
13
qemu-img were left passing NULL. As a result all errors went to
14
/dev/null instead of being reported to the user.
15
16
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
17
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
18
Reviewed-by: Markus Armbruster <armbru@redhat.com>
19
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
22
qemu-img.c | 26 +++++++++++++-------------
23
1 file changed, 13 insertions(+), 13 deletions(-)
24
25
diff --git a/qemu-img.c b/qemu-img.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/qemu-img.c
28
+++ b/qemu-img.c
29
@@ -XXX,XX +XXX,XX @@ static int img_create(int argc, char **argv)
30
31
if (qemu_opts_foreach(&qemu_object_opts,
32
user_creatable_add_opts_foreach,
33
- NULL, NULL)) {
34
+ NULL, &error_fatal)) {
35
goto fail;
36
}
37
38
@@ -XXX,XX +XXX,XX @@ static int img_check(int argc, char **argv)
39
40
if (qemu_opts_foreach(&qemu_object_opts,
41
user_creatable_add_opts_foreach,
42
- NULL, NULL)) {
43
+ NULL, &error_fatal)) {
44
return 1;
45
}
46
47
@@ -XXX,XX +XXX,XX @@ static int img_commit(int argc, char **argv)
48
49
if (qemu_opts_foreach(&qemu_object_opts,
50
user_creatable_add_opts_foreach,
51
- NULL, NULL)) {
52
+ NULL, &error_fatal)) {
53
return 1;
54
}
55
56
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
57
58
if (qemu_opts_foreach(&qemu_object_opts,
59
user_creatable_add_opts_foreach,
60
- NULL, NULL)) {
61
+ NULL, &error_fatal)) {
62
ret = 2;
63
goto out4;
64
}
65
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
66
67
if (qemu_opts_foreach(&qemu_object_opts,
68
user_creatable_add_opts_foreach,
69
- NULL, NULL)) {
70
+ NULL, &error_fatal)) {
71
goto fail_getopt;
72
}
73
74
@@ -XXX,XX +XXX,XX @@ static int img_info(int argc, char **argv)
75
76
if (qemu_opts_foreach(&qemu_object_opts,
77
user_creatable_add_opts_foreach,
78
- NULL, NULL)) {
79
+ NULL, &error_fatal)) {
80
return 1;
81
}
82
83
@@ -XXX,XX +XXX,XX @@ static int img_map(int argc, char **argv)
84
85
if (qemu_opts_foreach(&qemu_object_opts,
86
user_creatable_add_opts_foreach,
87
- NULL, NULL)) {
88
+ NULL, &error_fatal)) {
89
return 1;
90
}
91
92
@@ -XXX,XX +XXX,XX @@ static int img_snapshot(int argc, char **argv)
93
94
if (qemu_opts_foreach(&qemu_object_opts,
95
user_creatable_add_opts_foreach,
96
- NULL, NULL)) {
97
+ NULL, &error_fatal)) {
98
return 1;
99
}
100
101
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
102
103
if (qemu_opts_foreach(&qemu_object_opts,
104
user_creatable_add_opts_foreach,
105
- NULL, NULL)) {
106
+ NULL, &error_fatal)) {
107
return 1;
108
}
109
110
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
111
112
if (qemu_opts_foreach(&qemu_object_opts,
113
user_creatable_add_opts_foreach,
114
- NULL, NULL)) {
115
+ NULL, &error_fatal)) {
116
return 1;
117
}
118
119
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
120
121
if (qemu_opts_foreach(&qemu_object_opts,
122
user_creatable_add_opts_foreach,
123
- NULL, NULL)) {
124
+ NULL, &error_fatal)) {
125
ret = -1;
126
goto out_no_progress;
127
}
128
@@ -XXX,XX +XXX,XX @@ static int img_dd(int argc, char **argv)
129
130
if (qemu_opts_foreach(&qemu_object_opts,
131
user_creatable_add_opts_foreach,
132
- NULL, NULL)) {
133
+ NULL, &error_fatal)) {
134
ret = -1;
135
goto out;
136
}
137
@@ -XXX,XX +XXX,XX @@ static int img_measure(int argc, char **argv)
138
139
if (qemu_opts_foreach(&qemu_object_opts,
140
user_creatable_add_opts_foreach,
141
- NULL, NULL)) {
142
+ NULL, &error_fatal)) {
143
goto out;
144
}
145
146
--
147
2.20.1
148
149
diff view generated by jsdifflib
Deleted patch
1
nbd_client_attach_aio_context() schedules connection_co in the new
2
AioContext and this way reenters it in any arbitrary place that has
3
yielded. We can restrict this a bit to the function call where the
4
coroutine actually sits waiting when it's idle.
5
1
6
This doesn't solve any bug yet, but it shows where in the code we need
7
to support this random reentrance and where we don't have to care.
8
9
Add FIXME comments for the existing bugs that the rest of this series
10
will fix.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
---
15
block/nbd-client.h | 1 +
16
block/nbd-client.c | 22 ++++++++++++++++++++++
17
2 files changed, 23 insertions(+)
18
19
diff --git a/block/nbd-client.h b/block/nbd-client.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/nbd-client.h
22
+++ b/block/nbd-client.h
23
@@ -XXX,XX +XXX,XX @@ typedef struct NBDClientSession {
24
25
NBDClientRequest requests[MAX_NBD_REQUESTS];
26
NBDReply reply;
27
+ BlockDriverState *bs;
28
bool quit;
29
} NBDClientSession;
30
31
diff --git a/block/nbd-client.c b/block/nbd-client.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block/nbd-client.c
34
+++ b/block/nbd-client.c
35
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_connection_entry(void *opaque)
36
Error *local_err = NULL;
37
38
while (!s->quit) {
39
+ /*
40
+ * The NBD client can only really be considered idle when it has
41
+ * yielded from qio_channel_readv_all_eof(), waiting for data. This is
42
+ * the point where the additional scheduled coroutine entry happens
43
+ * after nbd_client_attach_aio_context().
44
+ *
45
+ * Therefore we keep an additional in_flight reference all the time and
46
+ * only drop it temporarily here.
47
+ *
48
+ * FIXME This is not safe because the QIOChannel could wake up the
49
+ * coroutine for a second time; it is not prepared for coroutine
50
+ * resumption from external code.
51
+ */
52
+ bdrv_dec_in_flight(s->bs);
53
assert(s->reply.handle == 0);
54
ret = nbd_receive_reply(s->ioc, &s->reply, &local_err);
55
+ bdrv_inc_in_flight(s->bs);
56
+
57
if (local_err) {
58
trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err));
59
error_free(local_err);
60
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_connection_entry(void *opaque)
61
62
s->quit = true;
63
nbd_recv_coroutines_wake_all(s);
64
+ bdrv_dec_in_flight(s->bs);
65
+
66
s->connection_co = NULL;
67
aio_wait_kick();
68
}
69
@@ -XXX,XX +XXX,XX @@ void nbd_client_attach_aio_context(BlockDriverState *bs,
70
{
71
NBDClientSession *client = nbd_get_client_session(bs);
72
qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc), new_context);
73
+
74
+ /* FIXME Really need a bdrv_inc_in_flight() here */
75
aio_co_schedule(new_context, client->connection_co);
76
}
77
78
@@ -XXX,XX +XXX,XX @@ static int nbd_client_connect(BlockDriverState *bs,
79
* kick the reply mechanism. */
80
qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL);
81
client->connection_co = qemu_coroutine_create(nbd_connection_entry, client);
82
+ bdrv_inc_in_flight(bs);
83
nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs));
84
85
logout("Established connection with NBD server\n");
86
@@ -XXX,XX +XXX,XX @@ int nbd_client_init(BlockDriverState *bs,
87
{
88
NBDClientSession *client = nbd_get_client_session(bs);
89
90
+ client->bs = bs;
91
qemu_co_mutex_init(&client->send_mutex);
92
qemu_co_queue_init(&client->free_sema);
93
94
--
95
2.20.1
96
97
diff view generated by jsdifflib
Deleted patch
1
Instead of using the convenience wrapper qio_channel_read_all_eof(), use
2
the lower level QIOChannel API. This means duplicating some code, but
3
we'll need this because this coroutine yield is special: We want it to
4
be interruptible so that nbd_client_attach_aio_context() can correctly
5
reenter the coroutine.
6
1
7
This moves the bdrv_dec/inc_in_flight() pair into nbd_read_eof(), so
8
that connection_co will always sit in this exact qio_channel_yield()
9
call when bdrv_drain() returns.
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
---
14
include/block/nbd.h | 4 ++--
15
block/nbd-client.c | 8 +-------
16
nbd/client.c | 46 ++++++++++++++++++++++++++++++++++++---------
17
3 files changed, 40 insertions(+), 18 deletions(-)
18
19
diff --git a/include/block/nbd.h b/include/block/nbd.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/nbd.h
22
+++ b/include/block/nbd.h
23
@@ -XXX,XX +XXX,XX @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
24
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
25
Error **errp);
26
int nbd_send_request(QIOChannel *ioc, NBDRequest *request);
27
-int coroutine_fn nbd_receive_reply(QIOChannel *ioc, NBDReply *reply,
28
- Error **errp);
29
+int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc,
30
+ NBDReply *reply, Error **errp);
31
int nbd_client(int fd);
32
int nbd_disconnect(int fd);
33
int nbd_errno_to_system_errno(int err);
34
diff --git a/block/nbd-client.c b/block/nbd-client.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/nbd-client.c
37
+++ b/block/nbd-client.c
38
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_connection_entry(void *opaque)
39
*
40
* Therefore we keep an additional in_flight reference all the time and
41
* only drop it temporarily here.
42
- *
43
- * FIXME This is not safe because the QIOChannel could wake up the
44
- * coroutine for a second time; it is not prepared for coroutine
45
- * resumption from external code.
46
*/
47
- bdrv_dec_in_flight(s->bs);
48
assert(s->reply.handle == 0);
49
- ret = nbd_receive_reply(s->ioc, &s->reply, &local_err);
50
- bdrv_inc_in_flight(s->bs);
51
+ ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, &local_err);
52
53
if (local_err) {
54
trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err));
55
diff --git a/nbd/client.c b/nbd/client.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/nbd/client.c
58
+++ b/nbd/client.c
59
@@ -XXX,XX +XXX,XX @@ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc,
60
* negative errno on failure (errp is set)
61
*/
62
static inline int coroutine_fn
63
-nbd_read_eof(QIOChannel *ioc, void *buffer, size_t size, Error **errp)
64
+nbd_read_eof(BlockDriverState *bs, QIOChannel *ioc, void *buffer, size_t size,
65
+ Error **errp)
66
{
67
- int ret;
68
+ bool partial = false;
69
70
assert(size);
71
- ret = qio_channel_read_all_eof(ioc, buffer, size, errp);
72
- if (ret < 0) {
73
- ret = -EIO;
74
+ while (size > 0) {
75
+ struct iovec iov = { .iov_base = buffer, .iov_len = size };
76
+ ssize_t len;
77
+
78
+ len = qio_channel_readv(ioc, &iov, 1, errp);
79
+ if (len == QIO_CHANNEL_ERR_BLOCK) {
80
+ bdrv_dec_in_flight(bs);
81
+ qio_channel_yield(ioc, G_IO_IN);
82
+ bdrv_inc_in_flight(bs);
83
+ continue;
84
+ } else if (len < 0) {
85
+ return -EIO;
86
+ } else if (len == 0) {
87
+ if (partial) {
88
+ error_setg(errp,
89
+ "Unexpected end-of-file before all bytes were read");
90
+ return -EIO;
91
+ } else {
92
+ return 0;
93
+ }
94
+ }
95
+
96
+ partial = true;
97
+ size -= len;
98
+ buffer = (uint8_t*) buffer + len;
99
}
100
- return ret;
101
+ return 1;
102
}
103
104
/* nbd_receive_reply
105
+ *
106
+ * Decreases bs->in_flight while waiting for a new reply. This yield is where
107
+ * we wait indefinitely and the coroutine must be able to be safely reentered
108
+ * for nbd_client_attach_aio_context().
109
+ *
110
* Returns 1 on success
111
* 0 on eof, when no data was read (errp is not set)
112
* negative errno on failure (errp is set)
113
*/
114
-int coroutine_fn nbd_receive_reply(QIOChannel *ioc, NBDReply *reply,
115
- Error **errp)
116
+int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc,
117
+ NBDReply *reply, Error **errp)
118
{
119
int ret;
120
const char *type;
121
122
- ret = nbd_read_eof(ioc, &reply->magic, sizeof(reply->magic), errp);
123
+ ret = nbd_read_eof(bs, ioc, &reply->magic, sizeof(reply->magic), errp);
124
if (ret <= 0) {
125
return ret;
126
}
127
--
128
2.20.1
129
130
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
bdrv_check_perm in it's recursion checks each node in context of new
4
permissions for one parent, because of nature of DFS. It works well,
5
while children subgraph of top-most updated node is a tree, i.e. it
6
doesn't have any kind of loops. But if we have a loop (not oriented,
7
of course), i.e. we have two different ways from top-node to some
8
child-node, then bdrv_check_perm will do wrong thing:
9
10
top
11
| \
12
| |
13
v v
14
A B
15
| |
16
v v
17
node
18
19
It will once check new permissions of node in context of new A
20
permissions and old B permissions and once visa-versa. It's a wrong way
21
and may lead to corruption of permission system. We may start with
22
no-permissions and all-shared for both A->node and B->node relations
23
and finish up with non shared write permission for both ways.
24
25
The following commit will add a test, which shows this bug.
26
27
To fix this situation, let's really set BdrvChild permissions during
28
bdrv_check_perm procedure. And we are happy here, as check-perm is
29
already written in transaction manner, so we just need to restore
30
backed-up permissions in _abort.
31
32
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
33
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
---
35
include/block/block_int.h | 5 +++++
36
block.c | 27 ++++++++++++++++++++++++++-
37
2 files changed, 31 insertions(+), 1 deletion(-)
38
39
diff --git a/include/block/block_int.h b/include/block/block_int.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/include/block/block_int.h
42
+++ b/include/block/block_int.h
43
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
44
*/
45
uint64_t shared_perm;
46
47
+ /* backup of permissions during permission update procedure */
48
+ bool has_backup_perm;
49
+ uint64_t backup_perm;
50
+ uint64_t backup_shared_perm;
51
+
52
QLIST_ENTRY(BdrvChild) next;
53
QLIST_ENTRY(BdrvChild) next_parent;
54
};
55
diff --git a/block.c b/block.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block.c
58
+++ b/block.c
59
@@ -XXX,XX +XXX,XX @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
60
ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, errp);
61
g_slist_free(ignore_children);
62
63
- return ret;
64
+ if (ret < 0) {
65
+ return ret;
66
+ }
67
+
68
+ if (!c->has_backup_perm) {
69
+ c->has_backup_perm = true;
70
+ c->backup_perm = c->perm;
71
+ c->backup_shared_perm = c->shared_perm;
72
+ }
73
+ /*
74
+ * Note: it's OK if c->has_backup_perm was already set, as we can find the
75
+ * same child twice during check_perm procedure
76
+ */
77
+
78
+ c->perm = perm;
79
+ c->shared_perm = shared;
80
+
81
+ return 0;
82
}
83
84
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
85
{
86
uint64_t cumulative_perms, cumulative_shared_perms;
87
88
+ c->has_backup_perm = false;
89
+
90
c->perm = perm;
91
c->shared_perm = shared;
92
93
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
94
95
static void bdrv_child_abort_perm_update(BdrvChild *c)
96
{
97
+ if (c->has_backup_perm) {
98
+ c->perm = c->backup_perm;
99
+ c->shared_perm = c->backup_shared_perm;
100
+ c->has_backup_perm = false;
101
+ }
102
+
103
bdrv_abort_perm_update(c->bs);
104
}
105
106
--
107
2.20.1
108
109
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
L1 table entries have a field to store the offset of an L2 table.
4
The rest of the bits of the entry are currently reserved except from
5
bit 63, which stores the COPIED flag.
6
7
The offset is always taken from the entry using L1E_OFFSET_MASK to
8
ensure that we only use the bits that belong to that field.
9
10
While that mask is used every time we read from the L1 table, it is
11
never used when we write to it. Due to the limits set elsewhere in the
12
code QEMU can never produce L2 table offsets that don't fit in that
13
field so any such offset when allocating an L2 table would indicate a
14
bug in QEMU.
15
16
Signed-off-by: Alberto Garcia <berto@igalia.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
block/qcow2-cluster.c | 3 +++
21
1 file changed, 3 insertions(+)
22
23
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/qcow2-cluster.c
26
+++ b/block/qcow2-cluster.c
27
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index)
28
goto fail;
29
}
30
31
+ /* The offset must fit in the offset field of the L1 table entry */
32
+ assert((l2_offset & L1E_OFFSET_MASK) == l2_offset);
33
+
34
/* If we're allocating the table at offset 0 then something is wrong */
35
if (l2_offset == 0) {
36
qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid "
37
--
38
2.20.1
39
40
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
bdrv_refresh_filename() should simply skip all implicit nodes. They are
4
supposed to be invisible to the user, so they should not appear in
5
filename information.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Message-id: 20190201192935.18394-4-mreitz@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block.c | 14 ++++++++++++++
14
1 file changed, 14 insertions(+)
15
16
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
19
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
21
bdrv_refresh_filename(child->bs);
22
}
23
24
+ if (bs->implicit) {
25
+ /* For implicit nodes, just copy everything from the single child */
26
+ child = QLIST_FIRST(&bs->children);
27
+ assert(QLIST_NEXT(child, next) == NULL);
28
+
29
+ pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
30
+ child->bs->exact_filename);
31
+ pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename);
32
+
33
+ bs->full_open_options = qobject_ref(child->bs->full_open_options);
34
+
35
+ return;
36
+ }
37
+
38
if (drv->bdrv_refresh_filename) {
39
/* Obsolete information is of no use here, so drop the old file name
40
* information before refreshing it */
41
--
42
2.20.1
43
44
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
If the backing file is overridden, this most probably does change the
4
guest-visible data of a BDS. Therefore, we will need to consider this
5
in bdrv_refresh_filename().
6
7
To see whether it has been overridden, we might want to compare
8
bs->backing_file and bs->backing->bs->filename. However,
9
bs->backing_file is changed by bdrv_set_backing_hd() (which is just used
10
to change the backing child at runtime, without modifying the image
11
header), so bs->backing_file most of the time simply contains a copy of
12
bs->backing->bs->filename anyway, so it is useless for such a
13
comparison.
14
15
This patch adds an auto_backing_file BDS field which contains the
16
backing file path as indicated by the image header, which is not changed
17
by bdrv_set_backing_hd().
18
19
Because of bdrv_refresh_filename() magic, however, a BDS's filename may
20
differ from what has been specified during bdrv_open(). Then, the
21
comparison between bs->auto_backing_file and bs->backing->bs->filename
22
may fail even though bs->backing was opened from bs->auto_backing_file.
23
To mitigate this, we can copy the real BDS's filename (after the whole
24
bdrv_open() and bdrv_refresh_filename() process) into
25
bs->auto_backing_file, if we know the former has been opened based on
26
the latter. This is only possible if no options modifying the backing
27
file's behavior have been specified, though. To simplify things, this
28
patch only copies the filename from the backing file if no options have
29
been specified for it at all.
30
31
Furthermore, there are cases where an overlay is created by qemu which
32
already contains a BDS's filename (e.g. in blockdev-snapshot-sync). We
33
do not need to worry about updating the overlay's bs->auto_backing_file
34
there, because we actually wrote a post-bdrv_refresh_filename() filename
35
into the image header.
36
37
So all in all, there will be false negatives where (as of a future
38
patch) bdrv_refresh_filename() will assume that the backing file differs
39
from what was specified in the image header, even though it really does
40
not. However, these cases should be limited to where (1) the user
41
actually did override something in the backing chain (e.g. by specifying
42
options for the backing file), or (2) the user executed a QMP command to
43
change some node's backing file (e.g. change-backing-file or
44
block-commit with @backing-file given) where the given filename does not
45
happen to coincide with qemu's idea of the backing BDS's filename.
46
47
Then again, (1) really is limited to -drive. With -blockdev or
48
blockdev-add, you have to adhere to the schema, so a user cannot give
49
partial "unimportant" options (e.g. by just setting backing.node-name
50
and leaving the rest to the image header). Therefore, trying to fix
51
this would mean trying to fix something for -drive only.
52
53
To improve on (2), we would need a full infrastructure to "canonicalize"
54
an arbitrary filename (+ options), so it can be compared against
55
another. That seems a bit over the top, considering that filenames
56
nowadays are there mostly for the user's entertainment.
57
58
Signed-off-by: Max Reitz <mreitz@redhat.com>
59
Reviewed-by: Eric Blake <eblake@redhat.com>
60
Reviewed-by: Alberto Garcia <berto@igalia.com>
61
Message-id: 20190201192935.18394-5-mreitz@redhat.com
62
Signed-off-by: Max Reitz <mreitz@redhat.com>
63
---
64
include/block/block_int.h | 4 ++++
65
block.c | 19 +++++++++++++++++++
66
block/qcow.c | 7 +++++--
67
block/qcow2.c | 10 +++++++---
68
block/qed.c | 7 +++++--
69
block/vmdk.c | 6 ++++--
70
6 files changed, 44 insertions(+), 9 deletions(-)
71
72
diff --git a/include/block/block_int.h b/include/block/block_int.h
73
index XXXXXXX..XXXXXXX 100644
74
--- a/include/block/block_int.h
75
+++ b/include/block/block_int.h
76
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
77
char filename[PATH_MAX];
78
char backing_file[PATH_MAX]; /* if non zero, the image is a diff of
79
this file image */
80
+ /* The backing filename indicated by the image header; if we ever
81
+ * open this file, then this is replaced by the resulting BDS's
82
+ * filename (i.e. after a bdrv_refresh_filename() run). */
83
+ char auto_backing_file[PATH_MAX];
84
char backing_format[16]; /* if non-zero and backing_file exists */
85
86
QDict *full_open_options;
87
diff --git a/block.c b/block.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/block.c
90
+++ b/block.c
91
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
92
char *bdref_key_dot;
93
const char *reference = NULL;
94
int ret = 0;
95
+ bool implicit_backing = false;
96
BlockDriverState *backing_hd;
97
QDict *options;
98
QDict *tmp_parent_options = NULL;
99
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
100
qobject_unref(options);
101
goto free_exit;
102
} else {
103
+ if (qdict_size(options) == 0) {
104
+ /* If the user specifies options that do not modify the
105
+ * backing file's behavior, we might still consider it the
106
+ * implicit backing file. But it's easier this way, and
107
+ * just specifying some of the backing BDS's options is
108
+ * only possible with -drive anyway (otherwise the QAPI
109
+ * schema forces the user to specify everything). */
110
+ implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file);
111
+ }
112
+
113
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX,
114
&local_err);
115
if (local_err) {
116
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
117
}
118
bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs));
119
120
+ if (implicit_backing) {
121
+ bdrv_refresh_filename(backing_hd);
122
+ pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
123
+ backing_hd->filename);
124
+ }
125
+
126
/* Hook up the backing file link; drop our reference, bs owns the
127
* backing_hd reference now */
128
bdrv_set_backing_hd(bs, backing_hd, &local_err);
129
@@ -XXX,XX +XXX,XX @@ int bdrv_change_backing_file(BlockDriverState *bs,
130
if (ret == 0) {
131
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
132
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
133
+ pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
134
+ backing_file ?: "");
135
}
136
return ret;
137
}
138
diff --git a/block/qcow.c b/block/qcow.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/qcow.c
141
+++ b/block/qcow.c
142
@@ -XXX,XX +XXX,XX @@
143
#include "qemu/module.h"
144
#include "qemu/option.h"
145
#include "qemu/bswap.h"
146
+#include "qemu/cutils.h"
147
#include <zlib.h>
148
#include "qapi/qmp/qdict.h"
149
#include "qapi/qmp/qstring.h"
150
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
151
goto fail;
152
}
153
ret = bdrv_pread(bs->file, header.backing_file_offset,
154
- bs->backing_file, len);
155
+ bs->auto_backing_file, len);
156
if (ret < 0) {
157
goto fail;
158
}
159
- bs->backing_file[len] = '\0';
160
+ bs->auto_backing_file[len] = '\0';
161
+ pstrcpy(bs->backing_file, sizeof(bs->backing_file),
162
+ bs->auto_backing_file);
163
}
164
165
/* Disable migration when qcow images are used */
166
diff --git a/block/qcow2.c b/block/qcow2.c
167
index XXXXXXX..XXXXXXX 100644
168
--- a/block/qcow2.c
169
+++ b/block/qcow2.c
170
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
171
goto fail;
172
}
173
ret = bdrv_pread(bs->file, header.backing_file_offset,
174
- bs->backing_file, len);
175
+ bs->auto_backing_file, len);
176
if (ret < 0) {
177
error_setg_errno(errp, -ret, "Could not read backing file name");
178
goto fail;
179
}
180
- bs->backing_file[len] = '\0';
181
- s->image_backing_file = g_strdup(bs->backing_file);
182
+ bs->auto_backing_file[len] = '\0';
183
+ pstrcpy(bs->backing_file, sizeof(bs->backing_file),
184
+ bs->auto_backing_file);
185
+ s->image_backing_file = g_strdup(bs->auto_backing_file);
186
}
187
188
/* Internal snapshots */
189
@@ -XXX,XX +XXX,XX @@ static int qcow2_change_backing_file(BlockDriverState *bs,
190
return -EINVAL;
191
}
192
193
+ pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
194
+ backing_file ?: "");
195
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
196
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
197
198
diff --git a/block/qed.c b/block/qed.c
199
index XXXXXXX..XXXXXXX 100644
200
--- a/block/qed.c
201
+++ b/block/qed.c
202
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
203
}
204
205
ret = qed_read_string(bs->file, s->header.backing_filename_offset,
206
- s->header.backing_filename_size, bs->backing_file,
207
- sizeof(bs->backing_file));
208
+ s->header.backing_filename_size,
209
+ bs->auto_backing_file,
210
+ sizeof(bs->auto_backing_file));
211
if (ret < 0) {
212
return ret;
213
}
214
+ pstrcpy(bs->backing_file, sizeof(bs->backing_file),
215
+ bs->auto_backing_file);
216
217
if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) {
218
pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw");
219
diff --git a/block/vmdk.c b/block/vmdk.c
220
index XXXXXXX..XXXXXXX 100644
221
--- a/block/vmdk.c
222
+++ b/block/vmdk.c
223
@@ -XXX,XX +XXX,XX @@ static int vmdk_parent_open(BlockDriverState *bs)
224
ret = -EINVAL;
225
goto out;
226
}
227
- if ((end_name - p_name) > sizeof(bs->backing_file) - 1) {
228
+ if ((end_name - p_name) > sizeof(bs->auto_backing_file) - 1) {
229
ret = -EINVAL;
230
goto out;
231
}
232
233
- pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
234
+ pstrcpy(bs->auto_backing_file, end_name - p_name + 1, p_name);
235
+ pstrcpy(bs->backing_file, sizeof(bs->backing_file),
236
+ bs->auto_backing_file);
237
}
238
239
out:
240
--
241
2.20.1
242
243
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Basically, bdrv_refresh_filename() should respect all children of a
4
BlockDriverState. However, generally those children are driver-specific,
5
so this function cannot handle the general case. On the other hand,
6
there are only few drivers which use other children than @file and
7
@backing (that being vmdk, quorum, and blkverify).
8
9
Most block drivers only use @file and/or @backing (if they use any
10
children at all). Both can be implemented directly in
11
bdrv_refresh_filename.
12
13
The user overriding the file's filename is already handled, however, the
14
user overriding the backing file is not. If this is done, opening the
15
BDS with the plain filename of its file will not be correct, so we may
16
not set bs->exact_filename in that case.
17
18
iotest 051 contains test cases for overriding the backing file, and so
19
its output changes with this patch applied.
20
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
Reviewed-by: Alberto Garcia <berto@igalia.com>
23
Message-id: 20190201192935.18394-6-mreitz@redhat.com
24
Signed-off-by: Max Reitz <mreitz@redhat.com>
25
---
26
block.c | 38 ++++++++++++++++++++++++++++++++++-
27
tests/qemu-iotests/051.out | 8 ++++----
28
tests/qemu-iotests/051.pc.out | 8 ++++----
29
3 files changed, 45 insertions(+), 9 deletions(-)
30
31
diff --git a/block.c b/block.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block.c
34
+++ b/block.c
35
@@ -XXX,XX +XXX,XX @@ static bool append_open_options(QDict *d, BlockDriverState *bs)
36
return found_any;
37
}
38
39
+/* Note: This function may return false positives; it may return true
40
+ * even if opening the backing file specified by bs's image header
41
+ * would result in exactly bs->backing. */
42
+static bool bdrv_backing_overridden(BlockDriverState *bs)
43
+{
44
+ if (bs->backing) {
45
+ return strcmp(bs->auto_backing_file,
46
+ bs->backing->bs->filename);
47
+ } else {
48
+ /* No backing BDS, so if the image header reports any backing
49
+ * file, it must have been suppressed */
50
+ return bs->auto_backing_file[0] != '\0';
51
+ }
52
+}
53
+
54
/* Updates the following BDS fields:
55
* - exact_filename: A filename which may be used for opening a block device
56
* which (mostly) equals the given BDS (even without any
57
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
58
BlockDriver *drv = bs->drv;
59
BdrvChild *child;
60
QDict *opts;
61
+ bool backing_overridden;
62
63
if (!drv) {
64
return;
65
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
66
return;
67
}
68
69
+ backing_overridden = bdrv_backing_overridden(bs);
70
+
71
+ if (bs->open_flags & BDRV_O_NO_IO) {
72
+ /* Without I/O, the backing file does not change anything.
73
+ * Therefore, in such a case (primarily qemu-img), we can
74
+ * pretend the backing file has not been overridden even if
75
+ * it technically has been. */
76
+ backing_overridden = false;
77
+ }
78
+
79
if (drv->bdrv_refresh_filename) {
80
/* Obsolete information is of no use here, so drop the old file name
81
* information before refreshing it */
82
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
83
84
opts = qdict_new();
85
has_open_options = append_open_options(opts, bs);
86
+ has_open_options |= backing_overridden;
87
88
/* If no specific options have been given for this BDS, the filename of
89
* the underlying file should suffice for this one as well */
90
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
91
* file BDS. The full options QDict of that file BDS should somehow
92
* contain a representation of the filename, therefore the following
93
* suffices without querying the (exact_)filename of this BDS. */
94
- if (bs->file->bs->full_open_options) {
95
+ if (bs->file->bs->full_open_options &&
96
+ (!bs->backing || bs->backing->bs->full_open_options))
97
+ {
98
qdict_put_str(opts, "driver", drv->format_name);
99
qdict_put(opts, "file",
100
qobject_ref(bs->file->bs->full_open_options));
101
102
+ if (bs->backing) {
103
+ qdict_put(opts, "backing",
104
+ qobject_ref(bs->backing->bs->full_open_options));
105
+ } else if (backing_overridden) {
106
+ qdict_put_null(opts, "backing");
107
+ }
108
+
109
bs->full_open_options = opts;
110
} else {
111
qobject_unref(opts);
112
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
113
index XXXXXXX..XXXXXXX 100644
114
--- a/tests/qemu-iotests/051.out
115
+++ b/tests/qemu-iotests/051.out
116
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
117
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults
118
QEMU X.Y.Z monitor - type 'help' for more information
119
(qemu) info block
120
-drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
121
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.orig"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
122
Removable device: not locked, tray closed
123
Cache mode: writeback
124
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
125
@@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
126
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
127
QEMU X.Y.Z monitor - type 'help' for more information
128
(qemu) info block
129
-drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
130
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
131
Removable device: not locked, tray closed
132
Cache mode: writeback
133
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
134
@@ -XXX,XX +XXX,XX @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
135
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
136
QEMU X.Y.Z monitor - type 'help' for more information
137
(qemu) info block
138
-drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
139
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
140
Removable device: not locked, tray closed
141
Cache mode: writethrough
142
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
143
@@ -XXX,XX +XXX,XX @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
144
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
145
QEMU X.Y.Z monitor - type 'help' for more information
146
(qemu) info block
147
-drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
148
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
149
Removable device: not locked, tray closed
150
Cache mode: writeback, ignore flushes
151
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
152
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
153
index XXXXXXX..XXXXXXX 100644
154
--- a/tests/qemu-iotests/051.pc.out
155
+++ b/tests/qemu-iotests/051.pc.out
156
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
157
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults
158
QEMU X.Y.Z monitor - type 'help' for more information
159
(qemu) info block
160
-drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
161
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.orig"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
162
Removable device: not locked, tray closed
163
Cache mode: writeback
164
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
165
@@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
166
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
167
QEMU X.Y.Z monitor - type 'help' for more information
168
(qemu) info block
169
-drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
170
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
171
Removable device: not locked, tray closed
172
Cache mode: writeback
173
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
174
@@ -XXX,XX +XXX,XX @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
175
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
176
QEMU X.Y.Z monitor - type 'help' for more information
177
(qemu) info block
178
-drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
179
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
180
Removable device: not locked, tray closed
181
Cache mode: writethrough
182
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
183
@@ -XXX,XX +XXX,XX @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
184
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
185
QEMU X.Y.Z monitor - type 'help' for more information
186
(qemu) info block
187
-drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
188
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
189
Removable device: not locked, tray closed
190
Cache mode: writeback, ignore flushes
191
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
192
--
193
2.20.1
194
195
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Message-id: 20190201192935.18394-7-mreitz@redhat.com
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/iotests.py | 10 ++++++++++
9
1 file changed, 10 insertions(+)
10
11
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
12
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/iotests.py
14
+++ b/tests/qemu-iotests/iotests.py
15
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
16
lines.append(line)
17
return '\n'.join(lines)
18
19
+def filter_imgfmt(msg):
20
+ return msg.replace(imgfmt, 'IMGFMT')
21
+
22
+def filter_qmp_imgfmt(qmsg):
23
+ def _filter(key, value):
24
+ if is_str(value):
25
+ return filter_imgfmt(value)
26
+ return value
27
+ return filter_qmp(qmsg, _filter)
28
+
29
def log(msg, filters=[], indent=None):
30
'''Logs either a string message or a JSON serializable message (like QMP).
31
If indent is provided, JSON serializable messages are pretty-printed.'''
32
--
33
2.20.1
34
35
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
This function queries a node; since we cannot do that right now, it
4
executes query-named-block-nodes and returns the matching node's object.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Message-id: 20190201192935.18394-8-mreitz@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
tests/qemu-iotests/iotests.py | 7 +++++++
14
1 file changed, 7 insertions(+)
15
16
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
17
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/iotests.py
19
+++ b/tests/qemu-iotests/iotests.py
20
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
21
else:
22
iotests.log(ev)
23
24
+ def node_info(self, node_name):
25
+ nodes = self.qmp('query-named-block-nodes')
26
+ for x in nodes['return']:
27
+ if x['node-name'] == node_name:
28
+ return x
29
+ return None
30
+
31
32
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
33
34
--
35
2.20.1
36
37
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Message-id: 20190201192935.18394-9-mreitz@redhat.com
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
7
tests/qemu-iotests/228 | 242 +++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/228.out | 84 +++++++++++++
9
tests/qemu-iotests/group | 1 +
10
3 files changed, 327 insertions(+)
11
create mode 100755 tests/qemu-iotests/228
12
create mode 100644 tests/qemu-iotests/228.out
13
14
diff --git a/tests/qemu-iotests/228 b/tests/qemu-iotests/228
15
new file mode 100755
16
index XXXXXXX..XXXXXXX
17
--- /dev/null
18
+++ b/tests/qemu-iotests/228
19
@@ -XXX,XX +XXX,XX @@
20
+#!/usr/bin/env python
21
+#
22
+# Test for when a backing file is considered overridden (thus, a
23
+# json:{} filename is generated for the overlay) and when it is not
24
+#
25
+# Copyright (C) 2018 Red Hat, Inc.
26
+#
27
+# This program is free software; you can redistribute it and/or modify
28
+# it under the terms of the GNU General Public License as published by
29
+# the Free Software Foundation; either version 2 of the License, or
30
+# (at your option) any later version.
31
+#
32
+# This program is distributed in the hope that it will be useful,
33
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
34
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
+# GNU General Public License for more details.
36
+#
37
+# You should have received a copy of the GNU General Public License
38
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
39
+#
40
+# Creator/Owner: Max Reitz <mreitz@redhat.com>
41
+
42
+import iotests
43
+from iotests import log, qemu_img, filter_testfiles, filter_imgfmt, \
44
+ filter_qmp_testfiles, filter_qmp_imgfmt
45
+
46
+# Need backing file and change-backing-file support
47
+iotests.verify_image_format(supported_fmts=['qcow2', 'qed'])
48
+iotests.verify_platform(['linux'])
49
+
50
+
51
+def log_node_info(node):
52
+ log('')
53
+
54
+ log('bs->filename: ' + node['image']['filename'],
55
+ filters=[filter_testfiles, filter_imgfmt])
56
+ log('bs->backing_file: ' + node['backing_file'],
57
+ filters=[filter_testfiles, filter_imgfmt])
58
+
59
+ if 'backing-image' in node['image']:
60
+ log('bs->backing->bs->filename: ' +
61
+ node['image']['backing-image']['filename'],
62
+ filters=[filter_testfiles, filter_imgfmt])
63
+ else:
64
+ log('bs->backing: (none)')
65
+
66
+ log('')
67
+
68
+
69
+with iotests.FilePath('base.img') as base_img_path, \
70
+ iotests.FilePath('top.img') as top_img_path, \
71
+ iotests.VM() as vm:
72
+
73
+ assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0
74
+ # Choose a funny way to describe the backing filename
75
+ assert qemu_img('create', '-f', iotests.imgfmt, '-b',
76
+ 'file:' + base_img_path, top_img_path) == 0
77
+
78
+ vm.launch()
79
+
80
+ log('--- Implicit backing file ---')
81
+ log('')
82
+
83
+ vm.qmp_log('blockdev-add',
84
+ node_name='node0',
85
+ driver=iotests.imgfmt,
86
+ file={
87
+ 'driver': 'file',
88
+ 'filename': top_img_path
89
+ },
90
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
91
+
92
+ # Filename should be plain, and the backing filename should not
93
+ # contain the "file:" prefix
94
+ log_node_info(vm.node_info('node0'))
95
+
96
+ vm.qmp_log('blockdev-del', node_name='node0')
97
+
98
+ log('')
99
+ log('--- change-backing-file ---')
100
+ log('')
101
+
102
+ vm.qmp_log('blockdev-add',
103
+ node_name='node0',
104
+ driver=iotests.imgfmt,
105
+ file={
106
+ 'driver': 'file',
107
+ 'filename': top_img_path
108
+ },
109
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
110
+
111
+ # Changing the backing file to a qemu-reported filename should
112
+ # result in qemu accepting the corresponding BDS as the implicit
113
+ # backing BDS (and thus not generate a json:{} filename).
114
+ # So, first, query the backing filename.
115
+
116
+ backing_filename = \
117
+ vm.node_info('node0')['image']['backing-image']['filename']
118
+
119
+ # Next, change the backing file to something different
120
+
121
+ vm.qmp_log('change-backing-file',
122
+ image_node_name='node0',
123
+ device='node0',
124
+ backing_file='null-co://',
125
+ filters=[filter_qmp_testfiles])
126
+
127
+ # Now, verify that we get a json:{} filename
128
+ # (Image header says "null-co://", actual backing file still is
129
+ # base_img_path)
130
+
131
+ log_node_info(vm.node_info('node0'))
132
+
133
+ # Change it back
134
+ # (To get header and backing file in sync)
135
+
136
+ vm.qmp_log('change-backing-file',
137
+ image_node_name='node0',
138
+ device='node0',
139
+ backing_file=backing_filename,
140
+ filters=[filter_qmp_testfiles])
141
+
142
+ # And verify that we get our original results
143
+
144
+ log_node_info(vm.node_info('node0'))
145
+
146
+ # Finally, try a "file:" prefix. While this is actually what we
147
+ # originally had in the image header, qemu will not reopen the
148
+ # backing file here, so it cannot verify that this filename
149
+ # "resolves" to the actual backing BDS's filename and will thus
150
+ # consider both to be different.
151
+ # (This may be fixed in the future.)
152
+
153
+ vm.qmp_log('change-backing-file',
154
+ image_node_name='node0',
155
+ device='node0',
156
+ backing_file=('file:' + backing_filename),
157
+ filters=[filter_qmp_testfiles])
158
+
159
+ # So now we should get a json:{} filename
160
+
161
+ log_node_info(vm.node_info('node0'))
162
+
163
+ # Remove and re-attach so we can see that (as in our first try),
164
+ # opening the image anew helps qemu resolve the header backing
165
+ # filename.
166
+
167
+ vm.qmp_log('blockdev-del', node_name='node0')
168
+
169
+ vm.qmp_log('blockdev-add',
170
+ node_name='node0',
171
+ driver=iotests.imgfmt,
172
+ file={
173
+ 'driver': 'file',
174
+ 'filename': top_img_path
175
+ },
176
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
177
+
178
+ log_node_info(vm.node_info('node0'))
179
+
180
+ vm.qmp_log('blockdev-del', node_name='node0')
181
+
182
+ log('')
183
+ log('--- Override backing file ---')
184
+ log('')
185
+
186
+ # For this test, we need the plain filename in the image header
187
+ # (because qemu cannot "canonicalize"/"resolve" the backing
188
+ # filename unless the backing file is opened implicitly with the
189
+ # overlay)
190
+ assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path,
191
+ top_img_path) == 0
192
+
193
+ # You can only reliably override backing options by using a node
194
+ # reference (or by specifying file.filename, but, well...)
195
+ vm.qmp_log('blockdev-add', node_name='null', driver='null-co')
196
+
197
+ vm.qmp_log('blockdev-add',
198
+ node_name='node0',
199
+ driver=iotests.imgfmt,
200
+ file={
201
+ 'driver': 'file',
202
+ 'filename': top_img_path
203
+ },
204
+ backing='null',
205
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
206
+
207
+ # Should get a json:{} filename (and bs->backing_file is
208
+ # null-co://, because that field actually has not much to do
209
+ # with the header backing filename (except that it is changed by
210
+ # change-backing-file))
211
+
212
+ log_node_info(vm.node_info('node0'))
213
+
214
+ # Detach the backing file by reopening the whole thing
215
+
216
+ vm.qmp_log('blockdev-del', node_name='node0')
217
+ vm.qmp_log('blockdev-del', node_name='null')
218
+
219
+ vm.qmp_log('blockdev-add',
220
+ node_name='node0',
221
+ driver=iotests.imgfmt,
222
+ file={
223
+ 'driver': 'file',
224
+ 'filename': top_img_path
225
+ },
226
+ backing=None,
227
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
228
+
229
+ # Should get a json:{} filename (because we overrode the backing
230
+ # file to not be there)
231
+
232
+ log_node_info(vm.node_info('node0'))
233
+
234
+ # Open the original backing file
235
+
236
+ vm.qmp_log('blockdev-add',
237
+ node_name='original-backing',
238
+ driver=iotests.imgfmt,
239
+ file={
240
+ 'driver': 'file',
241
+ 'filename': base_img_path
242
+ },
243
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
244
+
245
+ # Attach the original backing file to its overlay
246
+
247
+ vm.qmp_log('blockdev-snapshot',
248
+ node='original-backing',
249
+ overlay='node0')
250
+
251
+ # This should give us the original plain result
252
+ # FIXME: Currently, the block layer considers the runtime backing
253
+ # file to be different from the image header, which is
254
+ # wrong. This is fixed by a future patch.
255
+
256
+ log_node_info(vm.node_info('node0'))
257
+
258
+ vm.qmp_log('blockdev-del', node_name='node0')
259
+ vm.qmp_log('blockdev-del', node_name='original-backing')
260
+
261
+ vm.shutdown()
262
diff --git a/tests/qemu-iotests/228.out b/tests/qemu-iotests/228.out
263
new file mode 100644
264
index XXXXXXX..XXXXXXX
265
--- /dev/null
266
+++ b/tests/qemu-iotests/228.out
267
@@ -XXX,XX +XXX,XX @@
268
+--- Implicit backing file ---
269
+
270
+{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
271
+{"return": {}}
272
+
273
+bs->filename: TEST_DIR/PID-top.img
274
+bs->backing_file: TEST_DIR/PID-base.img
275
+bs->backing->bs->filename: TEST_DIR/PID-base.img
276
+
277
+{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
278
+{"return": {}}
279
+
280
+--- change-backing-file ---
281
+
282
+{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
283
+{"return": {}}
284
+{"execute": "change-backing-file", "arguments": {"backing-file": "null-co://", "device": "node0", "image-node-name": "node0"}}
285
+{"return": {}}
286
+
287
+bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
288
+bs->backing_file: null-co://
289
+bs->backing->bs->filename: TEST_DIR/PID-base.img
290
+
291
+{"execute": "change-backing-file", "arguments": {"backing-file": "TEST_DIR/PID-base.img", "device": "node0", "image-node-name": "node0"}}
292
+{"return": {}}
293
+
294
+bs->filename: TEST_DIR/PID-top.img
295
+bs->backing_file: TEST_DIR/PID-base.img
296
+bs->backing->bs->filename: TEST_DIR/PID-base.img
297
+
298
+{"execute": "change-backing-file", "arguments": {"backing-file": "file:TEST_DIR/PID-base.img", "device": "node0", "image-node-name": "node0"}}
299
+{"return": {}}
300
+
301
+bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
302
+bs->backing_file: file:TEST_DIR/PID-base.img
303
+bs->backing->bs->filename: TEST_DIR/PID-base.img
304
+
305
+{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
306
+{"return": {}}
307
+{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
308
+{"return": {}}
309
+
310
+bs->filename: TEST_DIR/PID-top.img
311
+bs->backing_file: TEST_DIR/PID-base.img
312
+bs->backing->bs->filename: TEST_DIR/PID-base.img
313
+
314
+{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
315
+{"return": {}}
316
+
317
+--- Override backing file ---
318
+
319
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "null"}}
320
+{"return": {}}
321
+{"execute": "blockdev-add", "arguments": {"backing": "null", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
322
+{"return": {}}
323
+
324
+bs->filename: json:{"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
325
+bs->backing_file: null-co://
326
+bs->backing->bs->filename: null-co://
327
+
328
+{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
329
+{"return": {}}
330
+{"execute": "blockdev-del", "arguments": {"node-name": "null"}}
331
+{"return": {}}
332
+{"execute": "blockdev-add", "arguments": {"backing": null, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
333
+{"return": {}}
334
+
335
+bs->filename: json:{"backing": null, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
336
+bs->backing_file: TEST_DIR/PID-base.img
337
+bs->backing: (none)
338
+
339
+{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "original-backing"}}
340
+{"return": {}}
341
+{"execute": "blockdev-snapshot", "arguments": {"node": "original-backing", "overlay": "node0"}}
342
+{"return": {}}
343
+
344
+bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
345
+bs->backing_file: TEST_DIR/PID-base.img
346
+bs->backing->bs->filename: TEST_DIR/PID-base.img
347
+
348
+{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
349
+{"return": {}}
350
+{"execute": "blockdev-del", "arguments": {"node-name": "original-backing"}}
351
+{"return": {}}
352
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
353
index XXXXXXX..XXXXXXX 100644
354
--- a/tests/qemu-iotests/group
355
+++ b/tests/qemu-iotests/group
356
@@ -XXX,XX +XXX,XX @@
357
225 rw auto quick
358
226 auto quick
359
227 auto quick
360
+228 rw auto quick
361
229 auto quick
362
231 auto quick
363
232 auto quick
364
--
365
2.20.1
366
367
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
The bdrv_reopen*() implementation doesn't like it if the graph is
2
changed between queuing nodes for reopen and actually reopening them
3
(one of the reasons is that queuing can be recursive).
2
4
3
bdrv_find_backing_image() should use bdrv_get_full_backing_filename() or
5
So instead of draining the device only in bdrv_reopen_multiple(),
4
bdrv_make_absolute_filename() instead of trying to do what those
6
require that callers already drained all affected nodes, and assert this
5
functions do by itself.
7
in bdrv_reopen_queue().
6
8
7
path_combine_deprecated() can now be dropped, so let's do that.
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
10
Reviewed-by: Fam Zheng <famz@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Message-id: 20190201192935.18394-14-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
11
---
14
block.c | 33 ++++++++++-----------------------
12
block.c | 23 ++++++++++++++++-------
15
1 file changed, 10 insertions(+), 23 deletions(-)
13
block/replication.c | 6 ++++++
14
qemu-io-cmds.c | 3 +++
15
3 files changed, 25 insertions(+), 7 deletions(-)
16
16
17
diff --git a/block.c b/block.c
17
diff --git a/block.c b/block.c
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block.c
19
--- a/block.c
20
+++ b/block.c
20
+++ b/block.c
21
@@ -XXX,XX +XXX,XX @@ char *path_combine(const char *base_path, const char *filename)
21
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
22
return result;
22
* returns a pointer to bs_queue, which is either the newly allocated
23
* bs_queue, or the existing bs_queue being used.
24
*
25
+ * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple().
26
*/
27
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
28
BlockDriverState *bs,
29
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
30
BdrvChild *child;
31
QDict *old_options, *explicit_options;
32
33
+ /* Make sure that the caller remembered to use a drained section. This is
34
+ * important to avoid graph changes between the recursive queuing here and
35
+ * bdrv_reopen_multiple(). */
36
+ assert(bs->quiesce_counter > 0);
37
+
38
if (bs_queue == NULL) {
39
bs_queue = g_new0(BlockReopenQueue, 1);
40
QSIMPLEQ_INIT(bs_queue);
41
@@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
42
* If all devices prepare successfully, then the changes are committed
43
* to all devices.
44
*
45
+ * All affected nodes must be drained between bdrv_reopen_queue() and
46
+ * bdrv_reopen_multiple().
47
*/
48
int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp)
49
{
50
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
51
52
assert(bs_queue != NULL);
53
54
- aio_context_release(ctx);
55
- bdrv_drain_all_begin();
56
- aio_context_acquire(ctx);
57
-
58
QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
59
+ assert(bs_entry->state.bs->quiesce_counter > 0);
60
if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) {
61
error_propagate(errp, local_err);
62
goto cleanup;
63
@@ -XXX,XX +XXX,XX @@ cleanup:
64
}
65
g_free(bs_queue);
66
67
- bdrv_drain_all_end();
68
-
69
return ret;
23
}
70
}
24
71
25
-static void path_combine_deprecated(char *dest, int dest_size,
72
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
26
- const char *base_path,
73
{
27
- const char *filename)
74
int ret = -1;
28
-{
75
Error *local_err = NULL;
29
- char *combined = path_combine(base_path, filename);
76
- BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
30
- pstrcpy(dest, dest_size, combined);
77
+ BlockReopenQueue *queue;
31
- g_free(combined);
78
32
-}
79
+ bdrv_subtree_drained_begin(bs);
33
-
80
+
34
/*
81
+ queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
35
* Helper function for bdrv_parse_filename() implementations to remove optional
82
ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err);
36
* protocol prefixes (especially "file:") from a filename and for putting the
83
if (local_err != NULL) {
37
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
84
error_propagate(errp, local_err);
38
85
}
39
filename_full = g_malloc(PATH_MAX);
86
+
40
backing_file_full = g_malloc(PATH_MAX);
87
+ bdrv_subtree_drained_end(bs);
41
- filename_tmp = g_malloc(PATH_MAX);
88
+
42
89
return ret;
43
is_protocol = path_has_protocol(backing_file);
44
45
- /* This will recursively refresh everything in the backing chain */
46
- bdrv_refresh_filename(bs);
47
-
48
for (curr_bs = bs; curr_bs->backing; curr_bs = curr_bs->backing->bs) {
49
50
/* If either of the filename paths is actually a protocol, then
51
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
52
} else {
53
/* If not an absolute filename path, make it relative to the current
54
* image's filename path */
55
- path_combine_deprecated(filename_tmp, PATH_MAX, curr_bs->filename,
56
- backing_file);
57
-
58
- /* We are going to compare absolute pathnames */
59
- if (!realpath(filename_tmp, filename_full)) {
60
+ filename_tmp = bdrv_make_absolute_filename(curr_bs, backing_file,
61
+ NULL);
62
+ /* We are going to compare canonicalized absolute pathnames */
63
+ if (!filename_tmp || !realpath(filename_tmp, filename_full)) {
64
+ g_free(filename_tmp);
65
continue;
66
}
67
+ g_free(filename_tmp);
68
69
/* We need to make sure the backing filename we are comparing against
70
* is relative to the current image filename (or absolute) */
71
- path_combine_deprecated(filename_tmp, PATH_MAX, curr_bs->filename,
72
- curr_bs->backing_file);
73
-
74
- if (!realpath(filename_tmp, backing_file_full)) {
75
+ filename_tmp = bdrv_get_full_backing_filename(curr_bs, NULL);
76
+ if (!filename_tmp || !realpath(filename_tmp, backing_file_full)) {
77
+ g_free(filename_tmp);
78
continue;
79
}
80
+ g_free(filename_tmp);
81
82
if (strcmp(backing_file_full, filename_full) == 0) {
83
retval = curr_bs->backing->bs;
84
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
85
86
g_free(filename_full);
87
g_free(backing_file_full);
88
- g_free(filename_tmp);
89
return retval;
90
}
90
}
91
91
92
diff --git a/block/replication.c b/block/replication.c
93
index XXXXXXX..XXXXXXX 100644
94
--- a/block/replication.c
95
+++ b/block/replication.c
96
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
97
new_secondary_flags = s->orig_secondary_flags;
98
}
99
100
+ bdrv_subtree_drained_begin(s->hidden_disk->bs);
101
+ bdrv_subtree_drained_begin(s->secondary_disk->bs);
102
+
103
if (orig_hidden_flags != new_hidden_flags) {
104
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
105
new_hidden_flags);
106
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
107
reopen_queue, &local_err);
108
error_propagate(errp, local_err);
109
}
110
+
111
+ bdrv_subtree_drained_end(s->hidden_disk->bs);
112
+ bdrv_subtree_drained_end(s->secondary_disk->bs);
113
}
114
115
static void backup_job_cleanup(BlockDriverState *bs)
116
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
117
index XXXXXXX..XXXXXXX 100644
118
--- a/qemu-io-cmds.c
119
+++ b/qemu-io-cmds.c
120
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
121
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
122
qemu_opts_reset(&reopen_opts);
123
124
+ bdrv_subtree_drained_begin(bs);
125
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
126
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
127
+ bdrv_subtree_drained_end(bs);
128
+
129
if (local_err) {
130
error_report_err(local_err);
131
} else {
92
--
132
--
93
2.20.1
133
2.13.6
94
134
95
135
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
blkverify's BDSs have a file BDS, but we do not want this to be
4
preferred over the raw node. There is no way to decide between the two
5
(and not really a reason to, either), so just return NULL in blkverify's
6
implementation of bdrv_dirname().
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Message-id: 20190201192935.18394-16-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/blkverify.c | 10 ++++++++++
15
1 file changed, 10 insertions(+)
16
17
diff --git a/block/blkverify.c b/block/blkverify.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/blkverify.c
20
+++ b/block/blkverify.c
21
@@ -XXX,XX +XXX,XX @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
22
}
23
}
24
25
+static char *blkverify_dirname(BlockDriverState *bs, Error **errp)
26
+{
27
+ /* In general, there are two BDSs with different dirnames below this one;
28
+ * so there is no unique dirname we could return (unless both are equal by
29
+ * chance). Therefore, to be consistent, just always return NULL. */
30
+ error_setg(errp, "Cannot generate a base directory for blkverify nodes");
31
+ return NULL;
32
+}
33
+
34
static BlockDriver bdrv_blkverify = {
35
.format_name = "blkverify",
36
.protocol_name = "blkverify",
37
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkverify = {
38
.bdrv_child_perm = bdrv_filter_default_perms,
39
.bdrv_getlength = blkverify_getlength,
40
.bdrv_refresh_filename = blkverify_refresh_filename,
41
+ .bdrv_dirname = blkverify_dirname,
42
43
.bdrv_co_preadv = blkverify_co_preadv,
44
.bdrv_co_pwritev = blkverify_co_pwritev,
45
--
46
2.20.1
47
48
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
While the common implementation for bdrv_dirname() should return NULL
4
for quorum BDSs already (because they do not have a file node and their
5
exact_filename field should be empty), there is no reason not to make
6
that explicit.
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Message-id: 20190201192935.18394-17-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/quorum.c | 11 +++++++++++
15
1 file changed, 11 insertions(+)
16
17
diff --git a/block/quorum.c b/block/quorum.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/quorum.c
20
+++ b/block/quorum.c
21
@@ -XXX,XX +XXX,XX @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
22
bs->full_open_options = opts;
23
}
24
25
+static char *quorum_dirname(BlockDriverState *bs, Error **errp)
26
+{
27
+ /* In general, there are multiple BDSs with different dirnames below this
28
+ * one; so there is no unique dirname we could return (unless all are equal
29
+ * by chance, or there is only one). Therefore, to be consistent, just
30
+ * always return NULL. */
31
+ error_setg(errp, "Cannot generate a base directory for quorum nodes");
32
+ return NULL;
33
+}
34
+
35
static BlockDriver bdrv_quorum = {
36
.format_name = "quorum",
37
38
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_quorum = {
39
.bdrv_open = quorum_open,
40
.bdrv_close = quorum_close,
41
.bdrv_refresh_filename = quorum_refresh_filename,
42
+ .bdrv_dirname = quorum_dirname,
43
44
.bdrv_co_flush_to_disk = quorum_co_flush,
45
46
--
47
2.20.1
48
49
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
The generic bdrv_dirname() implementation would be able to generate some
4
form of directory name for many NBD nodes, but it would be always wrong.
5
Therefore, we have to explicitly make it an error (until NBD has some
6
form of specification for export paths, if it ever will).
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Message-id: 20190201192935.18394-18-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/nbd.c | 13 +++++++++++++
15
1 file changed, 13 insertions(+)
16
17
diff --git a/block/nbd.c b/block/nbd.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/nbd.c
20
+++ b/block/nbd.c
21
@@ -XXX,XX +XXX,XX @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
22
bs->full_open_options = opts;
23
}
24
25
+static char *nbd_dirname(BlockDriverState *bs, Error **errp)
26
+{
27
+ /* The generic bdrv_dirname() implementation is able to work out some
28
+ * directory name for NBD nodes, but that would be wrong. So far there is no
29
+ * specification for how "export paths" would work, so NBD does not have
30
+ * directory names. */
31
+ error_setg(errp, "Cannot generate a base directory for NBD nodes");
32
+ return NULL;
33
+}
34
+
35
static BlockDriver bdrv_nbd = {
36
.format_name = "nbd",
37
.protocol_name = "nbd",
38
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nbd = {
39
.bdrv_attach_aio_context = nbd_attach_aio_context,
40
.bdrv_refresh_filename = nbd_refresh_filename,
41
.bdrv_co_block_status = nbd_client_co_block_status,
42
+ .bdrv_dirname = nbd_dirname,
43
};
44
45
static BlockDriver bdrv_nbd_tcp = {
46
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nbd_tcp = {
47
.bdrv_attach_aio_context = nbd_attach_aio_context,
48
.bdrv_refresh_filename = nbd_refresh_filename,
49
.bdrv_co_block_status = nbd_client_co_block_status,
50
+ .bdrv_dirname = nbd_dirname,
51
};
52
53
static BlockDriver bdrv_nbd_unix = {
54
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nbd_unix = {
55
.bdrv_attach_aio_context = nbd_attach_aio_context,
56
.bdrv_refresh_filename = nbd_refresh_filename,
57
.bdrv_co_block_status = nbd_client_co_block_status,
58
+ .bdrv_dirname = nbd_dirname,
59
};
60
61
static void bdrv_nbd_init(void)
62
--
63
2.20.1
64
65
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
While the basic idea is obvious and could be handled by the default
4
bdrv_dirname() implementation, we cannot generate a directory name if
5
the gid or uid are set, so we have to explicitly return NULL in those
6
cases.
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Message-id: 20190201192935.18394-19-mreitz@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/nfs.c | 15 +++++++++++++++
14
1 file changed, 15 insertions(+)
15
16
diff --git a/block/nfs.c b/block/nfs.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/nfs.c
19
+++ b/block/nfs.c
20
@@ -XXX,XX +XXX,XX @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
21
bs->full_open_options = opts;
22
}
23
24
+static char *nfs_dirname(BlockDriverState *bs, Error **errp)
25
+{
26
+ NFSClient *client = bs->opaque;
27
+
28
+ if (client->uid || client->gid) {
29
+ bdrv_refresh_filename(bs);
30
+ error_setg(errp, "Cannot generate a base directory for NFS node '%s'",
31
+ bs->filename);
32
+ return NULL;
33
+ }
34
+
35
+ return g_strdup_printf("nfs://%s%s/", client->server->host, client->path);
36
+}
37
+
38
#ifdef LIBNFS_FEATURE_PAGECACHE
39
static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs,
40
Error **errp)
41
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
42
.bdrv_detach_aio_context = nfs_detach_aio_context,
43
.bdrv_attach_aio_context = nfs_attach_aio_context,
44
.bdrv_refresh_filename = nfs_refresh_filename,
45
+ .bdrv_dirname = nfs_dirname,
46
47
#ifdef LIBNFS_FEATURE_PAGECACHE
48
.bdrv_co_invalidate_cache = nfs_co_invalidate_cache,
49
--
50
2.20.1
51
52
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
bdrv_get_full_backing_filename_from_filename() breaks down when it comes
4
to JSON filenames. Using bdrv_dirname() as the basis is better because
5
since we have BDS, we can descend through the BDS tree to the protocol
6
layer, which gives us a greater probability of finding a non-JSON name;
7
also, bdrv_dirname() is more correct as it allows block drivers to
8
override the generation of that directory name in a protocol-specific
9
way.
10
11
We still need to keep bdrv_get_full_backing_filename_from_filename(),
12
though, because it has valid callers which need it during image creation
13
when no BDS is available yet.
14
15
This makes a test case in qemu-iotest 110, which was supposed to fail,
16
work. That is actually good, but we need to change the reference output
17
(and the comment in 110) accordingly.
18
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
Reviewed-by: Alberto Garcia <berto@igalia.com>
21
Message-id: 20190201192935.18394-20-mreitz@redhat.com
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
23
---
24
block.c | 20 +++++++++++++-------
25
tests/qemu-iotests/110 | 3 ++-
26
tests/qemu-iotests/110.out | 2 +-
27
3 files changed, 16 insertions(+), 9 deletions(-)
28
29
diff --git a/block.c b/block.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
32
+++ b/block.c
33
@@ -XXX,XX +XXX,XX @@ char *bdrv_get_full_backing_filename_from_filename(const char *backed,
34
static char *bdrv_make_absolute_filename(BlockDriverState *relative_to,
35
const char *filename, Error **errp)
36
{
37
- char *bs_filename;
38
+ char *dir, *full_name;
39
40
- bdrv_refresh_filename(relative_to);
41
+ if (!filename || filename[0] == '\0') {
42
+ return NULL;
43
+ } else if (path_has_protocol(filename) || path_is_absolute(filename)) {
44
+ return g_strdup(filename);
45
+ }
46
47
- bs_filename = relative_to->exact_filename[0]
48
- ? relative_to->exact_filename
49
- : relative_to->filename;
50
+ dir = bdrv_dirname(relative_to, errp);
51
+ if (!dir) {
52
+ return NULL;
53
+ }
54
55
- return bdrv_get_full_backing_filename_from_filename(bs_filename,
56
- filename ?: "", errp);
57
+ full_name = g_strconcat(dir, filename, NULL);
58
+ g_free(dir);
59
+ return full_name;
60
}
61
62
char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp)
63
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
64
index XXXXXXX..XXXXXXX 100755
65
--- a/tests/qemu-iotests/110
66
+++ b/tests/qemu-iotests/110
67
@@ -XXX,XX +XXX,XX @@ echo '=== Non-reconstructable filename ==='
68
echo
69
70
# Across blkdebug without a config file, you cannot reconstruct filenames, so
71
-# qemu is incapable of knowing the directory of the top image
72
+# qemu is incapable of knowing the directory of the top image from the filename
73
+# alone. However, using bdrv_dirname(), it should still work.
74
TEST_IMG="json:{
75
'driver': '$IMGFMT',
76
'file': {
77
diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out
78
index XXXXXXX..XXXXXXX 100644
79
--- a/tests/qemu-iotests/110.out
80
+++ b/tests/qemu-iotests/110.out
81
@@ -XXX,XX +XXX,XX @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
82
image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}
83
file format: IMGFMT
84
virtual size: 64M (67108864 bytes)
85
-backing file: t.IMGFMT.base (cannot determine actual path)
86
+backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
87
88
=== Backing name is always relative to the backed image ===
89
90
--
91
2.20.1
92
93
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Test 110 tests relative backing filenames for complex BDS trees. Now
4
that the originally supposedly failing test passes, let us add a new
5
failing test: Quorum can never work automatically (without detecting
6
whether all child nodes have the same base directory, but that would be
7
rather inconsistent behavior).
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Message-id: 20190201192935.18394-21-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
tests/qemu-iotests/110 | 26 ++++++++++++++++++++++++++
15
tests/qemu-iotests/110.out | 7 +++++++
16
2 files changed, 33 insertions(+)
17
18
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/110
21
+++ b/tests/qemu-iotests/110
22
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
23
_cleanup()
24
{
25
    _cleanup_test_img
26
+ rm -f "$TEST_IMG.copy"
27
}
28
trap "_cleanup; exit \$status" 0 1 2 3 15
29
30
@@ -XXX,XX +XXX,XX @@ echo
31
# omit the image size; it should work anyway
32
_make_test_img -b "$TEST_IMG_REL.base"
33
34
+echo
35
+echo '=== Nodes without a common directory ==='
36
+echo
37
+
38
+cp "$TEST_IMG" "$TEST_IMG.copy"
39
+
40
+# Should inform us that the actual path of the backing file cannot be determined
41
+TEST_IMG="json:{
42
+ 'driver': '$IMGFMT',
43
+ 'file': {
44
+ 'driver': 'quorum',
45
+ 'vote-threshold': 1,
46
+ 'children': [
47
+ {
48
+ 'driver': 'file',
49
+ 'filename': '$TEST_IMG'
50
+ },
51
+ {
52
+ 'driver': 'file',
53
+ 'filename': '$TEST_IMG.copy'
54
+ }
55
+ ]
56
+ }
57
+}" _img_info | _filter_img_info
58
+
59
60
# success, all done
61
echo '*** done'
62
diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out
63
index XXXXXXX..XXXXXXX 100644
64
--- a/tests/qemu-iotests/110.out
65
+++ b/tests/qemu-iotests/110.out
66
@@ -XXX,XX +XXX,XX @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
67
=== Backing name is always relative to the backed image ===
68
69
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base
70
+
71
+=== Nodes without a common directory ===
72
+
73
+image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "blkverify": false, "rewrite-corrupted": false, "vote-threshold": 1}}
74
+file format: IMGFMT
75
+virtual size: 64M (67108864 bytes)
76
+backing file: t.IMGFMT.base (cannot determine actual path)
77
*** done
78
--
79
2.20.1
80
81
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
If a format BDS's file BDS is in turn a format BDS, we cannot simply use
4
the same filename, because when opening a BDS tree based on a filename
5
alone, qemu will create only one format node on top of one protocol node
6
(disregarding a potential backing file).
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Message-id: 20190201192935.18394-26-mreitz@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block.c | 18 +++++++++++++++---
14
1 file changed, 15 insertions(+), 3 deletions(-)
15
16
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
19
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
21
22
bs->exact_filename[0] = '\0';
23
24
- /* If no specific options have been given for this BDS, the filename of
25
- * the underlying file should suffice for this one as well */
26
- if (bs->file->bs->exact_filename[0] && !generate_json_filename) {
27
+ /*
28
+ * We can use the underlying file's filename if:
29
+ * - it has a filename,
30
+ * - the file is a protocol BDS, and
31
+ * - opening that file (as this BDS's format) will automatically create
32
+ * the BDS tree we have right now, that is:
33
+ * - the user did not significantly change this BDS's behavior with
34
+ * some explicit (strong) options
35
+ * - no non-file child of this BDS has been overridden by the user
36
+ * Both of these conditions are represented by generate_json_filename.
37
+ */
38
+ if (bs->file->bs->exact_filename[0] &&
39
+ bs->file->bs->drv->bdrv_file_open &&
40
+ !generate_json_filename)
41
+ {
42
strcpy(bs->exact_filename, bs->file->bs->exact_filename);
43
}
44
}
45
--
46
2.20.1
47
48
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Currently, nvme's bdrv_refresh_filename() is an exact copy of null's
4
implementation. However, for null, "null-co://" and "null-aio://" are
5
indeed valid filenames -- for nvme, they are not, as a device address is
6
still required.
7
8
The correct implementation should generate a filename of the form
9
"nvme://[PCI address]/[namespace]" (as the comment above
10
nvme_parse_filename() describes).
11
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Alberto Garcia <berto@igalia.com>
14
Message-id: 20190201192935.18394-27-mreitz@redhat.com
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
block/nvme.c | 23 +++++++++--------------
18
1 file changed, 9 insertions(+), 14 deletions(-)
19
20
diff --git a/block/nvme.c b/block/nvme.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/nvme.c
23
+++ b/block/nvme.c
24
@@ -XXX,XX +XXX,XX @@ typedef struct {
25
26
/* Total size of mapped qiov, accessed under dma_map_lock */
27
int dma_map_count;
28
+
29
+ /* PCI address (required for nvme_refresh_filename()) */
30
+ char *device;
31
} BDRVNVMeState;
32
33
#define NVME_BLOCK_OPT_DEVICE "device"
34
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
35
36
qemu_co_mutex_init(&s->dma_map_lock);
37
qemu_co_queue_init(&s->dma_flush_queue);
38
+ s->device = g_strdup(device);
39
s->nsid = namespace;
40
s->aio_context = bdrv_get_aio_context(bs);
41
ret = event_notifier_init(&s->irq_notifier, 0);
42
@@ -XXX,XX +XXX,XX @@ static void nvme_close(BlockDriverState *bs)
43
event_notifier_cleanup(&s->irq_notifier);
44
qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE);
45
qemu_vfio_close(s->vfio);
46
+
47
+ g_free(s->device);
48
}
49
50
static int nvme_file_open(BlockDriverState *bs, QDict *options, int flags,
51
@@ -XXX,XX +XXX,XX @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state,
52
53
static void nvme_refresh_filename(BlockDriverState *bs)
54
{
55
- const QDictEntry *e;
56
-
57
- for (e = qdict_first(bs->full_open_options); e;
58
- e = qdict_next(bs->full_open_options, e))
59
- {
60
- /* These options can be ignored */
61
- if (strcmp(qdict_entry_key(e), "filename") &&
62
- strcmp(qdict_entry_key(e), "driver"))
63
- {
64
- return;
65
- }
66
- }
67
+ BDRVNVMeState *s = bs->opaque;
68
69
- snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
70
- bs->drv->format_name);
71
+ snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nvme://%s/%i",
72
+ s->device, s->nsid);
73
}
74
75
static void nvme_refresh_limits(BlockDriverState *bs, Error **errp)
76
--
77
2.20.1
78
79
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
Message-id: 20190201192935.18394-29-mreitz@redhat.com
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
block/curl.c | 21 +++++++++++++++++++++
9
1 file changed, 21 insertions(+)
10
11
diff --git a/block/curl.c b/block/curl.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/curl.c
14
+++ b/block/curl.c
15
@@ -XXX,XX +XXX,XX @@ static int64_t curl_getlength(BlockDriverState *bs)
16
return s->len;
17
}
18
19
+static void curl_refresh_filename(BlockDriverState *bs)
20
+{
21
+ BDRVCURLState *s = bs->opaque;
22
+
23
+ /* "readahead" and "timeout" do not change the guest-visible data,
24
+ * so ignore them */
25
+ if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT ||
26
+ s->cookie || s->username || s->password || s->proxyusername ||
27
+ s->proxypassword)
28
+ {
29
+ return;
30
+ }
31
+
32
+ pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url);
33
+}
34
+
35
+
36
static const char *const curl_strong_runtime_opts[] = {
37
CURL_BLOCK_OPT_URL,
38
CURL_BLOCK_OPT_SSLVERIFY,
39
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_http = {
40
.bdrv_detach_aio_context = curl_detach_aio_context,
41
.bdrv_attach_aio_context = curl_attach_aio_context,
42
43
+ .bdrv_refresh_filename = curl_refresh_filename,
44
.strong_runtime_opts = curl_strong_runtime_opts,
45
};
46
47
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_https = {
48
.bdrv_detach_aio_context = curl_detach_aio_context,
49
.bdrv_attach_aio_context = curl_attach_aio_context,
50
51
+ .bdrv_refresh_filename = curl_refresh_filename,
52
.strong_runtime_opts = curl_strong_runtime_opts,
53
};
54
55
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ftp = {
56
.bdrv_detach_aio_context = curl_detach_aio_context,
57
.bdrv_attach_aio_context = curl_attach_aio_context,
58
59
+ .bdrv_refresh_filename = curl_refresh_filename,
60
.strong_runtime_opts = curl_strong_runtime_opts,
61
};
62
63
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ftps = {
64
.bdrv_detach_aio_context = curl_detach_aio_context,
65
.bdrv_attach_aio_context = curl_attach_aio_context,
66
67
+ .bdrv_refresh_filename = curl_refresh_filename,
68
.strong_runtime_opts = curl_strong_runtime_opts,
69
};
70
71
--
72
2.20.1
73
74
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
While we cannot represent the latency-ns option in a filename, it is not
4
a strong option so not being able to should not stop us from generating
5
a filename nonetheless.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Message-id: 20190201192935.18394-30-mreitz@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/null.c | 3 ++-
13
1 file changed, 2 insertions(+), 1 deletion(-)
14
15
diff --git a/block/null.c b/block/null.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/null.c
18
+++ b/block/null.c
19
@@ -XXX,XX +XXX,XX @@ static void null_refresh_filename(BlockDriverState *bs)
20
{
21
/* These options can be ignored */
22
if (strcmp(qdict_entry_key(e), "filename") &&
23
- strcmp(qdict_entry_key(e), "driver"))
24
+ strcmp(qdict_entry_key(e), "driver") &&
25
+ strcmp(qdict_entry_key(e), NULL_OPT_LATENCY))
26
{
27
return;
28
}
29
--
30
2.20.1
31
32
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Message-id: 20190201192935.18394-32-mreitz@redhat.com
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
7
tests/qemu-iotests/224 | 139 +++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/224.out | 18 +++++
9
tests/qemu-iotests/group | 1 +
10
3 files changed, 158 insertions(+)
11
create mode 100755 tests/qemu-iotests/224
12
create mode 100644 tests/qemu-iotests/224.out
13
14
diff --git a/tests/qemu-iotests/224 b/tests/qemu-iotests/224
15
new file mode 100755
16
index XXXXXXX..XXXXXXX
17
--- /dev/null
18
+++ b/tests/qemu-iotests/224
19
@@ -XXX,XX +XXX,XX @@
20
+#!/usr/bin/env python
21
+#
22
+# Test json:{} filenames with qemu-internal BDSs
23
+# (the one of commit, to be precise)
24
+#
25
+# Copyright (C) 2018 Red Hat, Inc.
26
+#
27
+# This program is free software; you can redistribute it and/or modify
28
+# it under the terms of the GNU General Public License as published by
29
+# the Free Software Foundation; either version 2 of the License, or
30
+# (at your option) any later version.
31
+#
32
+# This program is distributed in the hope that it will be useful,
33
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
34
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
+# GNU General Public License for more details.
36
+#
37
+# You should have received a copy of the GNU General Public License
38
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
39
+#
40
+# Creator/Owner: Max Reitz <mreitz@redhat.com>
41
+
42
+import iotests
43
+from iotests import log, qemu_img, qemu_io_silent, filter_qmp_testfiles, \
44
+ filter_qmp_imgfmt
45
+import json
46
+
47
+# Need backing file support (for arbitrary backing formats)
48
+iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed'])
49
+iotests.verify_platform(['linux'])
50
+
51
+
52
+# There are two variations of this test:
53
+# (1) We do not set filter_node_name. In that case, the commit_top
54
+# driver should not appear anywhere.
55
+# (2) We do set filter_node_name. In that case, it should appear.
56
+#
57
+# This for loop executes both.
58
+for filter_node_name in False, True:
59
+ log('')
60
+ log('--- filter_node_name: %s ---' % filter_node_name)
61
+ log('')
62
+
63
+ with iotests.FilePath('base.img') as base_img_path, \
64
+ iotests.FilePath('mid.img') as mid_img_path, \
65
+ iotests.FilePath('top.img') as top_img_path, \
66
+ iotests.VM() as vm:
67
+
68
+ assert qemu_img('create', '-f', iotests.imgfmt,
69
+ base_img_path, '64M') == 0
70
+ assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path,
71
+ mid_img_path) == 0
72
+ assert qemu_img('create', '-f', iotests.imgfmt, '-b', mid_img_path,
73
+ top_img_path) == 0
74
+
75
+ # Something to commit
76
+ assert qemu_io_silent(mid_img_path, '-c', 'write -P 1 0 1M') == 0
77
+
78
+ vm.launch()
79
+
80
+ # Change the bottom-most image's backing file (to null-co://)
81
+ # to enforce json:{} filenames
82
+ vm.qmp_log('blockdev-add',
83
+ node_name='top',
84
+ driver=iotests.imgfmt,
85
+ file={
86
+ 'driver': 'file',
87
+ 'filename': top_img_path
88
+ },
89
+ backing={
90
+ 'node-name': 'mid',
91
+ 'driver': iotests.imgfmt,
92
+ 'file': {
93
+ 'driver': 'file',
94
+ 'filename': mid_img_path
95
+ },
96
+ 'backing': {
97
+ 'node-name': 'base',
98
+ 'driver': iotests.imgfmt,
99
+ 'file': {
100
+ 'driver': 'file',
101
+ 'filename': base_img_path
102
+ },
103
+ 'backing': {
104
+ 'driver': 'null-co'
105
+ }
106
+ }
107
+ },
108
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
109
+
110
+ # As long as block-commit does not accept node names, we have to
111
+ # get our mid/base filenames here
112
+ mid_name = vm.node_info('mid')['image']['filename']
113
+ base_name = vm.node_info('base')['image']['filename']
114
+
115
+ assert mid_name[:5] == 'json:'
116
+ assert base_name[:5] == 'json:'
117
+
118
+ # Start the block job
119
+ if filter_node_name:
120
+ vm.qmp_log('block-commit',
121
+ job_id='commit',
122
+ device='top',
123
+ filter_node_name='filter_node',
124
+ top=mid_name,
125
+ base=base_name,
126
+ speed=1,
127
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
128
+ else:
129
+ vm.qmp_log('block-commit',
130
+ job_id='commit',
131
+ device='top',
132
+ top=mid_name,
133
+ base=base_name,
134
+ speed=1,
135
+ filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
136
+
137
+ vm.qmp_log('job-pause', id='commit')
138
+
139
+ # Get and parse top's json:{} filename
140
+ top_name = vm.node_info('top')['image']['filename']
141
+
142
+ vm.shutdown()
143
+
144
+ assert top_name[:5] == 'json:'
145
+ top_options = json.loads(top_name[5:])
146
+
147
+ if filter_node_name:
148
+ # This should be present and set
149
+ assert top_options['backing']['driver'] == 'commit_top'
150
+ # And the mid image is commit_top's backing image
151
+ mid_options = top_options['backing']['backing']
152
+ else:
153
+ # The mid image should appear as the immediate backing BDS
154
+ # of top
155
+ mid_options = top_options['backing']
156
+
157
+ assert mid_options['driver'] == iotests.imgfmt
158
+ assert mid_options['file']['filename'] == mid_img_path
159
diff --git a/tests/qemu-iotests/224.out b/tests/qemu-iotests/224.out
160
new file mode 100644
161
index XXXXXXX..XXXXXXX
162
--- /dev/null
163
+++ b/tests/qemu-iotests/224.out
164
@@ -XXX,XX +XXX,XX @@
165
+
166
+--- filter_node_name: False ---
167
+
168
+{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "base"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-mid.img"}, "node-name": "mid"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "top"}}
169
+{"return": {}}
170
+{"execute": "block-commit", "arguments": {"base": "json:{\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}", "device": "top", "job-id": "commit", "speed": 1, "top": "json:{\"backing\": {\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-mid.img\"}}"}}
171
+{"return": {}}
172
+{"execute": "job-pause", "arguments": {"id": "commit"}}
173
+{"return": {}}
174
+
175
+--- filter_node_name: True ---
176
+
177
+{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "base"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-mid.img"}, "node-name": "mid"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "top"}}
178
+{"return": {}}
179
+{"execute": "block-commit", "arguments": {"base": "json:{\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}", "device": "top", "filter-node-name": "filter_node", "job-id": "commit", "speed": 1, "top": "json:{\"backing\": {\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-mid.img\"}}"}}
180
+{"return": {}}
181
+{"execute": "job-pause", "arguments": {"id": "commit"}}
182
+{"return": {}}
183
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
184
index XXXXXXX..XXXXXXX 100644
185
--- a/tests/qemu-iotests/group
186
+++ b/tests/qemu-iotests/group
187
@@ -XXX,XX +XXX,XX @@
188
221 rw auto quick
189
222 rw auto quick
190
223 rw auto quick
191
+224 rw auto quick
192
225 rw auto quick
193
226 auto quick
194
227 auto quick
195
--
196
2.20.1
197
198
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
A previous commit removed the default filters for qmp_log with the
4
intention to make them explicit; but this happened only for test 206.
5
There are more tests (for more exotic image formats than qcow2) which
6
require the filename filter, though.
7
8
Note that 237 is still broken for Python 2.x, which is fixed in the next
9
commit.
10
11
Fixes: f8ca8609d8549def45b28e82ecac64adaeee9f12
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: John Snow <jsnow@redhat.com>
14
Message-id: 20190210145736.1486-2-mreitz@redhat.com
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
tests/qemu-iotests/210 | 5 +++--
18
tests/qemu-iotests/211 | 5 +++--
19
tests/qemu-iotests/212 | 5 +++--
20
tests/qemu-iotests/213 | 5 +++--
21
tests/qemu-iotests/237 | 5 +++--
22
5 files changed, 15 insertions(+), 10 deletions(-)
23
24
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
25
index XXXXXXX..XXXXXXX 100755
26
--- a/tests/qemu-iotests/210
27
+++ b/tests/qemu-iotests/210
28
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['luks'])
29
iotests.verify_protocol(supported=['file'])
30
31
def blockdev_create(vm, options):
32
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
33
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
34
+ filters=[iotests.filter_qmp_testfiles])
35
36
if 'return' in result:
37
assert result['return'] == {}
38
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
39
'size': 0 })
40
41
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
42
- node_name='imgfile')
43
+ node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
44
45
blockdev_create(vm, { 'driver': imgfmt,
46
'file': 'imgfile',
47
diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211
48
index XXXXXXX..XXXXXXX 100755
49
--- a/tests/qemu-iotests/211
50
+++ b/tests/qemu-iotests/211
51
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['vdi'])
52
iotests.verify_protocol(supported=['file'])
53
54
def blockdev_create(vm, options):
55
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
56
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
57
+ filters=[iotests.filter_qmp_testfiles])
58
59
if 'return' in result:
60
assert result['return'] == {}
61
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vdi') as disk_path, \
62
'size': 0 })
63
64
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
65
- node_name='imgfile')
66
+ node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
67
68
blockdev_create(vm, { 'driver': imgfmt,
69
'file': 'imgfile',
70
diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212
71
index XXXXXXX..XXXXXXX 100755
72
--- a/tests/qemu-iotests/212
73
+++ b/tests/qemu-iotests/212
74
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['parallels'])
75
iotests.verify_protocol(supported=['file'])
76
77
def blockdev_create(vm, options):
78
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
79
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
80
+ filters=[iotests.filter_qmp_testfiles])
81
82
if 'return' in result:
83
assert result['return'] == {}
84
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.parallels') as disk_path, \
85
'size': 0 })
86
87
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
88
- node_name='imgfile')
89
+ node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
90
91
blockdev_create(vm, { 'driver': imgfmt,
92
'file': 'imgfile',
93
diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213
94
index XXXXXXX..XXXXXXX 100755
95
--- a/tests/qemu-iotests/213
96
+++ b/tests/qemu-iotests/213
97
@@ -XXX,XX +XXX,XX @@ iotests.verify_image_format(supported_fmts=['vhdx'])
98
iotests.verify_protocol(supported=['file'])
99
100
def blockdev_create(vm, options):
101
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
102
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
103
+ filters=[iotests.filter_qmp_testfiles])
104
105
if 'return' in result:
106
assert result['return'] == {}
107
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vhdx') as disk_path, \
108
'size': 0 })
109
110
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
111
- node_name='imgfile')
112
+ node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
113
114
blockdev_create(vm, { 'driver': imgfmt,
115
'file': 'imgfile',
116
diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237
117
index XXXXXXX..XXXXXXX 100755
118
--- a/tests/qemu-iotests/237
119
+++ b/tests/qemu-iotests/237
120
@@ -XXX,XX +XXX,XX @@ from iotests import imgfmt
121
iotests.verify_image_format(supported_fmts=['vmdk'])
122
123
def blockdev_create(vm, options):
124
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
125
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
126
+ filters=[iotests.filter_qmp_testfiles])
127
128
if 'return' in result:
129
assert result['return'] == {}
130
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
131
'size': 0 })
132
133
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
134
- node_name='imgfile')
135
+ node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
136
137
blockdev_create(vm, { 'driver': imgfmt,
138
'file': 'imgfile',
139
--
140
2.20.1
141
142
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
math.ceil() returns an integer on Python 3.x, but a float on Python 2.x.
4
range() always needs integers, so we need an explicit conversion on 2.x
5
(which does not hurt on 3.x).
6
7
It is not quite clear whether we want to support Python 2.x for any
8
prolonged time, but this may as well be fixed along with the other
9
issues some iotests have right now.
10
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Reviewed-by: John Snow <jsnow@redhat.com>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Message-id: 20190210145736.1486-3-mreitz@redhat.com
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
tests/qemu-iotests/237 | 2 +-
18
1 file changed, 1 insertion(+), 1 deletion(-)
19
20
diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237
21
index XXXXXXX..XXXXXXX 100755
22
--- a/tests/qemu-iotests/237
23
+++ b/tests/qemu-iotests/237
24
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \
25
iotests.log("= %s %d =" % (subfmt, size))
26
iotests.log("")
27
28
- num_extents = math.ceil(size / 2.0**31)
29
+ num_extents = int(math.ceil(size / 2.0**31))
30
extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ]
31
32
vm.launch()
33
--
34
2.20.1
35
36
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
This test creates no such file.
4
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Message-id: 20190210145736.1486-4-mreitz@redhat.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/232 | 1 -
12
1 file changed, 1 deletion(-)
13
14
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/232
17
+++ b/tests/qemu-iotests/232
18
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
19
_cleanup()
20
{
21
_cleanup_test_img
22
- rm -f $TEST_IMG.snap
23
}
24
trap "_cleanup; exit \$status" 0 1 2 3 15
25
26
--
27
2.20.1
28
29
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Fixes: 08fcd6111e1949f456e1b232ebeeb0cc17019a92
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: John Snow <jsnow@redhat.com>
6
Message-id: 20190210145736.1486-6-mreitz@redhat.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
tests/qemu-iotests/207 | 10 +++++++---
10
tests/qemu-iotests/207.out | 4 ++--
11
2 files changed, 9 insertions(+), 5 deletions(-)
12
13
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
14
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/207
16
+++ b/tests/qemu-iotests/207
17
@@ -XXX,XX +XXX,XX @@ import re
18
iotests.verify_image_format(supported_fmts=['raw'])
19
iotests.verify_protocol(supported=['ssh'])
20
21
-def filter_hash(msg):
22
- return re.sub('"hash": "[0-9a-f]+"', '"hash": HASH', msg)
23
+def filter_hash(qmsg):
24
+ def _filter(key, value):
25
+ if key == 'hash' and re.match('[0-9a-f]+', value):
26
+ return 'HASH'
27
+ return value
28
+ return iotests.filter_qmp(qmsg, _filter)
29
30
def blockdev_create(vm, options):
31
result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
32
- filters=[iotests.filter_testfiles, filter_hash])
33
+ filters=[iotests.filter_qmp_testfiles, filter_hash])
34
35
if 'return' in result:
36
assert result['return'] == {}
37
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
38
index XXXXXXX..XXXXXXX 100644
39
--- a/tests/qemu-iotests/207.out
40
+++ b/tests/qemu-iotests/207.out
41
@@ -XXX,XX +XXX,XX @@ Job failed: remote host key does not match host_key_check 'wrong'
42
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
43
{"return": {}}
44
45
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
46
+{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
47
{"return": {}}
48
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
49
{"return": {}}
50
@@ -XXX,XX +XXX,XX @@ Job failed: remote host key does not match host_key_check 'wrong'
51
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
52
{"return": {}}
53
54
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
55
+{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
56
{"return": {}}
57
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
58
{"return": {}}
59
--
60
2.20.1
61
62
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
filter_qmp_testfiles() currently filters the filename only for specific
4
keys. However, there are more keys that take filenames (such as
5
block-commit's @top and @base, or ssh's @path), and it does not make
6
sense to list them all here. "$TEST_DIR/$PID-" should have enough
7
entropy not to appear anywhere randomly.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
11
Message-id: 20190210145736.1486-8-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
tests/qemu-iotests/iotests.py | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
16
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
18
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/iotests.py
20
+++ b/tests/qemu-iotests/iotests.py
21
@@ -XXX,XX +XXX,XX @@ def filter_testfiles(msg):
22
23
def filter_qmp_testfiles(qmsg):
24
def _filter(key, value):
25
- if key == 'filename' or key == 'backing-file':
26
+ if is_str(value):
27
return filter_testfiles(value)
28
return value
29
return filter_qmp(qmsg, _filter)
30
--
31
2.20.1
32
33
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
8908b253c4ad5f8874c8d13abec169c696a5cd32 has implemented filtering of
4
remote paths for NFS, but forgot SSH. This patch takes care of that.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Message-id: 20190210145736.1486-9-mreitz@redhat.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/common.rc | 1 +
12
1 file changed, 1 insertion(+)
13
14
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/common.rc
17
+++ b/tests/qemu-iotests/common.rc
18
@@ -XXX,XX +XXX,XX @@ else
19
TEST_IMG="nbd:127.0.0.1:10810"
20
elif [ "$IMGPROTO" = "ssh" ]; then
21
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
22
+ REMOTE_TEST_DIR="ssh://127.0.0.1$TEST_DIR"
23
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
24
elif [ "$IMGPROTO" = "nfs" ]; then
25
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
26
--
27
2.20.1
28
29
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Adding a telnet monitor for no real purpose on a fixed port is not so
4
great. Just use a null monitor instead.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Message-id: 20190210145736.1486-10-mreitz@redhat.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
scripts/qemu.py | 5 ++---
12
tests/qemu-iotests/045 | 2 +-
13
2 files changed, 3 insertions(+), 4 deletions(-)
14
15
diff --git a/scripts/qemu.py b/scripts/qemu.py
16
index XXXXXXX..XXXXXXX 100644
17
--- a/scripts/qemu.py
18
+++ b/scripts/qemu.py
19
@@ -XXX,XX +XXX,XX @@ class QEMUMachine(object):
20
return False
21
22
# This can be used to add an unused monitor instance.
23
- def add_monitor_telnet(self, ip, port):
24
- args = 'tcp:%s:%d,server,nowait,telnet' % (ip, port)
25
+ def add_monitor_null(self):
26
self._args.append('-monitor')
27
- self._args.append(args)
28
+ self._args.append('null')
29
30
def add_fd(self, fd, fdset, opaque, opts=''):
31
"""
32
diff --git a/tests/qemu-iotests/045 b/tests/qemu-iotests/045
33
index XXXXXXX..XXXXXXX 100755
34
--- a/tests/qemu-iotests/045
35
+++ b/tests/qemu-iotests/045
36
@@ -XXX,XX +XXX,XX @@ class TestSCMFd(iotests.QMPTestCase):
37
qemu_img('create', '-f', iotests.imgfmt, image0, '128K')
38
# Add an unused monitor, to verify it works fine when two monitor
39
# instances present
40
- self.vm.add_monitor_telnet("0",4445)
41
+ self.vm.add_monitor_null()
42
self.vm.launch()
43
44
def tearDown(self):
45
--
46
2.20.1
47
48
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
This follows what qmp() does, so the output will correspond to the
4
actual QMP command.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Message-id: 20190210145736.1486-11-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/206.out | 56 +++++++++++++++++------------------
11
tests/qemu-iotests/207.out | 18 +++++------
12
tests/qemu-iotests/210.out | 28 +++++++++---------
13
tests/qemu-iotests/211.out | 26 ++++++++--------
14
tests/qemu-iotests/212.out | 44 +++++++++++++--------------
15
tests/qemu-iotests/213.out | 46 ++++++++++++++--------------
16
tests/qemu-iotests/237.out | 54 ++++++++++++++++-----------------
17
tests/qemu-iotests/iotests.py | 6 ++--
18
8 files changed, 140 insertions(+), 138 deletions(-)
19
20
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
21
index XXXXXXX..XXXXXXX 100644
22
--- a/tests/qemu-iotests/206.out
23
+++ b/tests/qemu-iotests/206.out
24
@@ -XXX,XX +XXX,XX @@
25
=== Successful image creation (defaults) ===
26
27
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}}
28
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}}
29
{"return": {}}
30
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
31
{"return": {}}
32
33
-{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node_name": "imgfile"}}
34
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node-name": "imgfile"}}
35
{"return": {}}
36
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}}
37
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}}
38
{"return": {}}
39
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
40
{"return": {}}
41
@@ -XXX,XX +XXX,XX @@ Format specific information:
42
43
=== Successful image creation (inline blockdev-add, explicit defaults) ===
44
45
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}}
46
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}}
47
{"return": {}}
48
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
49
{"return": {}}
50
51
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}}
52
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}}
53
{"return": {}}
54
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
55
{"return": {}}
56
@@ -XXX,XX +XXX,XX @@ Format specific information:
57
58
=== Successful image creation (v3 non-default options) ===
59
60
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}}
61
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}}
62
{"return": {}}
63
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
64
{"return": {}}
65
66
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}}
67
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}}
68
{"return": {}}
69
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
70
{"return": {}}
71
@@ -XXX,XX +XXX,XX @@ Format specific information:
72
73
=== Successful image creation (v2 non-default options) ===
74
75
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}}
76
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}}
77
{"return": {}}
78
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
79
{"return": {}}
80
81
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}}
82
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}}
83
{"return": {}}
84
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
85
{"return": {}}
86
@@ -XXX,XX +XXX,XX @@ Format specific information:
87
88
=== Successful image creation (encrypted) ===
89
90
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}}
91
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}}
92
{"return": {}}
93
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
94
{"return": {}}
95
@@ -XXX,XX +XXX,XX @@ Format specific information:
96
97
=== Invalid BlockdevRef ===
98
99
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}}
100
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}}
101
{"return": {}}
102
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
103
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
104
{"return": {}}
105
106
=== Invalid sizes ===
107
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}}
108
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}}
109
{"return": {}}
110
Job failed: Image size must be a multiple of 512 bytes
111
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
112
{"return": {}}
113
114
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}}
115
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}}
116
{"return": {}}
117
Job failed: Could not resize image: Image size cannot be negative
118
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
119
{"return": {}}
120
121
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}}
122
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}}
123
{"return": {}}
124
Job failed: Could not resize image: Image size cannot be negative
125
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
126
{"return": {}}
127
128
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}}
129
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}}
130
{"return": {}}
131
Job failed: Could not resize image: Failed to grow the L1 table: File too large
132
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
133
{"return": {}}
134
135
=== Invalid version ===
136
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}}
137
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}}
138
{"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}}
139
140
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}}
141
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}}
142
{"return": {}}
143
Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
144
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
145
{"return": {}}
146
147
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}}
148
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}}
149
{"return": {}}
150
Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
151
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
152
{"return": {}}
153
154
=== Invalid backing file options ===
155
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}}
156
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}}
157
{"return": {}}
158
Job failed: Backing file and preallocation cannot be used at the same time
159
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
160
{"return": {}}
161
162
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}}
163
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}}
164
{"return": {}}
165
Job failed: Backing format cannot be used without backing file
166
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
167
{"return": {}}
168
169
=== Invalid cluster size ===
170
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}}
171
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}}
172
{"return": {}}
173
Job failed: Cluster size must be a power of two between 512 and 2048k
174
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
175
{"return": {}}
176
177
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}}
178
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}}
179
{"return": {}}
180
Job failed: Cluster size must be a power of two between 512 and 2048k
181
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
182
{"return": {}}
183
184
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}}
185
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}}
186
{"return": {}}
187
Job failed: Cluster size must be a power of two between 512 and 2048k
188
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
189
{"return": {}}
190
191
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}}
192
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}}
193
{"return": {}}
194
Job failed: Cluster size must be a power of two between 512 and 2048k
195
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
196
{"return": {}}
197
198
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}}
199
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}}
200
{"return": {}}
201
Job failed: Could not resize image: Failed to grow the L1 table: File too large
202
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
203
{"return": {}}
204
205
=== Invalid refcount width ===
206
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}}
207
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}}
208
{"return": {}}
209
Job failed: Refcount width must be a power of two and may not exceed 64 bits
210
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
211
{"return": {}}
212
213
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}}
214
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}}
215
{"return": {}}
216
Job failed: Refcount width must be a power of two and may not exceed 64 bits
217
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
218
{"return": {}}
219
220
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}}
221
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}}
222
{"return": {}}
223
Job failed: Refcount width must be a power of two and may not exceed 64 bits
224
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
225
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
226
index XXXXXXX..XXXXXXX 100644
227
--- a/tests/qemu-iotests/207.out
228
+++ b/tests/qemu-iotests/207.out
229
@@ -XXX,XX +XXX,XX @@
230
=== Successful image creation (defaults) ===
231
232
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
233
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
234
{"return": {}}
235
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
236
{"return": {}}
237
@@ -XXX,XX +XXX,XX @@ virtual size: 4.0M (4194304 bytes)
238
239
=== Test host-key-check options ===
240
241
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
242
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
243
{"return": {}}
244
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
245
{"return": {}}
246
@@ -XXX,XX +XXX,XX @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
247
file format: IMGFMT
248
virtual size: 8.0M (8388608 bytes)
249
250
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
251
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
252
{"return": {}}
253
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
254
{"return": {}}
255
@@ -XXX,XX +XXX,XX @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
256
file format: IMGFMT
257
virtual size: 4.0M (4194304 bytes)
258
259
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}}
260
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}}
261
{"return": {}}
262
Job failed: remote host key does not match host_key_check 'wrong'
263
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
264
{"return": {}}
265
266
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
267
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
268
{"return": {}}
269
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
270
{"return": {}}
271
@@ -XXX,XX +XXX,XX @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
272
file format: IMGFMT
273
virtual size: 8.0M (8388608 bytes)
274
275
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}}
276
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}}
277
{"return": {}}
278
Job failed: remote host key does not match host_key_check 'wrong'
279
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
280
{"return": {}}
281
282
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
283
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
284
{"return": {}}
285
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
286
{"return": {}}
287
@@ -XXX,XX +XXX,XX @@ virtual size: 4.0M (4194304 bytes)
288
289
=== Invalid path and user ===
290
291
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
292
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
293
{"return": {}}
294
Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)
295
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
296
{"return": {}}
297
298
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}}
299
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}}
300
{"return": {}}
301
Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent
302
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
303
diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out
304
index XXXXXXX..XXXXXXX 100644
305
--- a/tests/qemu-iotests/210.out
306
+++ b/tests/qemu-iotests/210.out
307
@@ -XXX,XX +XXX,XX @@
308
=== Successful image creation (defaults) ===
309
310
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}}
311
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}}
312
{"return": {}}
313
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
314
{"return": {}}
315
316
-{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node_name": "imgfile"}}
317
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node-name": "imgfile"}}
318
{"return": {}}
319
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}}
320
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}}
321
{"return": {}}
322
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
323
{"return": {}}
324
@@ -XXX,XX +XXX,XX @@ Format specific information:
325
326
=== Successful image creation (with non-default options) ===
327
328
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}}
329
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}}
330
{"return": {}}
331
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
332
{"return": {}}
333
334
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}}
335
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}}
336
{"return": {}}
337
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
338
{"return": {}}
339
@@ -XXX,XX +XXX,XX @@ Format specific information:
340
341
=== Invalid BlockdevRef ===
342
343
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}}
344
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}}
345
{"return": {}}
346
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
347
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
348
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
349
350
=== Zero size ===
351
352
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}}
353
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}}
354
{"return": {}}
355
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
356
{"return": {}}
357
@@ -XXX,XX +XXX,XX @@ Format specific information:
358
359
=== Invalid sizes ===
360
361
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}}
362
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}}
363
{"return": {}}
364
Job failed: The requested file size is too large
365
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
366
{"return": {}}
367
368
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}}
369
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}}
370
{"return": {}}
371
Job failed: The requested file size is too large
372
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
373
{"return": {}}
374
375
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}}
376
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}}
377
{"return": {}}
378
Job failed: The requested file size is too large
379
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
380
@@ -XXX,XX +XXX,XX @@ Job failed: The requested file size is too large
381
382
=== Resize image with invalid sizes ===
383
384
-{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775296}}
385
+{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775296}}
386
{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
387
-{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775808}}
388
+{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775808}}
389
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
390
-{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 18446744073709551104}}
391
+{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 18446744073709551104}}
392
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
393
-{"execute": "block_resize", "arguments": {"node_name": "node1", "size": -9223372036854775808}}
394
+{"execute": "block_resize", "arguments": {"node-name": "node1", "size": -9223372036854775808}}
395
{"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}}
396
image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
397
file format: IMGFMT
398
diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out
399
index XXXXXXX..XXXXXXX 100644
400
--- a/tests/qemu-iotests/211.out
401
+++ b/tests/qemu-iotests/211.out
402
@@ -XXX,XX +XXX,XX @@
403
=== Successful image creation (defaults) ===
404
405
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
406
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
407
{"return": {}}
408
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
409
{"return": {}}
410
411
-{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node_name": "imgfile"}}
412
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node-name": "imgfile"}}
413
{"return": {}}
414
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}}
415
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}}
416
{"return": {}}
417
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
418
{"return": {}}
419
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
420
421
=== Successful image creation (explicit defaults) ===
422
423
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
424
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
425
{"return": {}}
426
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
427
{"return": {}}
428
429
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}}
430
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}}
431
{"return": {}}
432
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
433
{"return": {}}
434
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
435
436
=== Successful image creation (with non-default options) ===
437
438
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
439
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
440
{"return": {}}
441
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
442
{"return": {}}
443
444
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}}
445
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}}
446
{"return": {}}
447
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
448
{"return": {}}
449
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
450
451
=== Invalid BlockdevRef ===
452
453
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}}
454
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}}
455
{"return": {}}
456
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
457
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
458
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
459
460
=== Zero size ===
461
462
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}}
463
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}}
464
{"return": {}}
465
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
466
{"return": {}}
467
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
468
469
=== Maximum size ===
470
471
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}}
472
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}}
473
{"return": {}}
474
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
475
{"return": {}}
476
@@ -XXX,XX +XXX,XX @@ cluster_size: 1048576
477
478
=== Invalid sizes ===
479
480
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}}
481
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}}
482
{"return": {}}
483
Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)
484
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
485
{"return": {}}
486
487
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}}
488
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}}
489
{"return": {}}
490
Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)
491
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
492
{"return": {}}
493
494
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}}
495
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}}
496
{"return": {}}
497
Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)
498
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
499
diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out
500
index XXXXXXX..XXXXXXX 100644
501
--- a/tests/qemu-iotests/212.out
502
+++ b/tests/qemu-iotests/212.out
503
@@ -XXX,XX +XXX,XX @@
504
=== Successful image creation (defaults) ===
505
506
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
507
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
508
{"return": {}}
509
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
510
{"return": {}}
511
512
-{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node_name": "imgfile"}}
513
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node-name": "imgfile"}}
514
{"return": {}}
515
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}}
516
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}}
517
{"return": {}}
518
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
519
{"return": {}}
520
@@ -XXX,XX +XXX,XX @@ virtual size: 128M (134217728 bytes)
521
522
=== Successful image creation (explicit defaults) ===
523
524
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
525
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
526
{"return": {}}
527
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
528
{"return": {}}
529
530
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}}
531
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}}
532
{"return": {}}
533
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
534
{"return": {}}
535
@@ -XXX,XX +XXX,XX @@ virtual size: 64M (67108864 bytes)
536
537
=== Successful image creation (with non-default options) ===
538
539
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
540
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
541
{"return": {}}
542
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
543
{"return": {}}
544
545
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}}
546
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}}
547
{"return": {}}
548
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
549
{"return": {}}
550
@@ -XXX,XX +XXX,XX @@ virtual size: 32M (33554432 bytes)
551
552
=== Invalid BlockdevRef ===
553
554
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}}
555
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}}
556
{"return": {}}
557
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
558
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
559
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
560
561
=== Zero size ===
562
563
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}}
564
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}}
565
{"return": {}}
566
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
567
{"return": {}}
568
@@ -XXX,XX +XXX,XX @@ virtual size: 0 (0 bytes)
569
570
=== Maximum size ===
571
572
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}}
573
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}}
574
{"return": {}}
575
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
576
{"return": {}}
577
@@ -XXX,XX +XXX,XX @@ virtual size: 4096T (4503599627369984 bytes)
578
579
=== Invalid sizes ===
580
581
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}}
582
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}}
583
{"return": {}}
584
Job failed: Image size must be a multiple of 512 bytes
585
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
586
{"return": {}}
587
588
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}}
589
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}}
590
{"return": {}}
591
Job failed: Image size is too large for this cluster size
592
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
593
{"return": {}}
594
595
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}}
596
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}}
597
{"return": {}}
598
Job failed: Image size is too large for this cluster size
599
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
600
{"return": {}}
601
602
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}}
603
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}}
604
{"return": {}}
605
Job failed: Image size is too large for this cluster size
606
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
607
{"return": {}}
608
609
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}}
610
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}}
611
{"return": {}}
612
Job failed: Image size is too large for this cluster size
613
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
614
@@ -XXX,XX +XXX,XX @@ Job failed: Image size is too large for this cluster size
615
616
=== Invalid cluster size ===
617
618
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}}
619
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}}
620
{"return": {}}
621
Job failed: Cluster size must be a multiple of 512 bytes
622
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
623
{"return": {}}
624
625
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}}
626
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}}
627
{"return": {}}
628
Job failed: Cluster size must be a multiple of 512 bytes
629
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
630
{"return": {}}
631
632
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}}
633
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}}
634
{"return": {}}
635
Job failed: Cluster size is too large
636
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
637
{"return": {}}
638
639
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}}
640
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}}
641
{"return": {}}
642
Job failed: Cluster size is too large
643
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
644
{"return": {}}
645
646
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}}
647
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}}
648
{"return": {}}
649
Job failed: Cluster size is too large
650
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
651
{"return": {}}
652
653
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}}
654
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}}
655
{"return": {}}
656
Job failed: Image size is too large for this cluster size
657
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
658
{"return": {}}
659
660
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}}
661
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}}
662
{"return": {}}
663
Job failed: Image size is too large for this cluster size
664
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
665
diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out
666
index XXXXXXX..XXXXXXX 100644
667
--- a/tests/qemu-iotests/213.out
668
+++ b/tests/qemu-iotests/213.out
669
@@ -XXX,XX +XXX,XX @@
670
=== Successful image creation (defaults) ===
671
672
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
673
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
674
{"return": {}}
675
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
676
{"return": {}}
677
678
-{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node_name": "imgfile"}}
679
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node-name": "imgfile"}}
680
{"return": {}}
681
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}}
682
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}}
683
{"return": {}}
684
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
685
{"return": {}}
686
@@ -XXX,XX +XXX,XX @@ cluster_size: 8388608
687
688
=== Successful image creation (explicit defaults) ===
689
690
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
691
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
692
{"return": {}}
693
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
694
{"return": {}}
695
696
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}}
697
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}}
698
{"return": {}}
699
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
700
{"return": {}}
701
@@ -XXX,XX +XXX,XX @@ cluster_size: 8388608
702
703
=== Successful image creation (with non-default options) ===
704
705
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
706
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
707
{"return": {}}
708
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
709
{"return": {}}
710
711
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}}
712
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}}
713
{"return": {}}
714
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
715
{"return": {}}
716
@@ -XXX,XX +XXX,XX @@ cluster_size: 268435456
717
718
=== Invalid BlockdevRef ===
719
720
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}}
721
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}}
722
{"return": {}}
723
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
724
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
725
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
726
727
=== Zero size ===
728
729
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}}
730
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}}
731
{"return": {}}
732
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
733
{"return": {}}
734
@@ -XXX,XX +XXX,XX @@ cluster_size: 8388608
735
736
=== Maximum size ===
737
738
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}}
739
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}}
740
{"return": {}}
741
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
742
{"return": {}}
743
@@ -XXX,XX +XXX,XX @@ cluster_size: 67108864
744
745
=== Invalid sizes ===
746
747
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}}
748
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}}
749
{"return": {}}
750
Job failed: Image size too large; max of 64TB
751
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
752
{"return": {}}
753
754
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}}
755
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}}
756
{"return": {}}
757
Job failed: Image size too large; max of 64TB
758
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
759
{"return": {}}
760
761
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}}
762
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}}
763
{"return": {}}
764
Job failed: Image size too large; max of 64TB
765
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
766
{"return": {}}
767
768
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}}
769
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}}
770
{"return": {}}
771
Job failed: Image size too large; max of 64TB
772
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
773
@@ -XXX,XX +XXX,XX @@ Job failed: Image size too large; max of 64TB
774
775
=== Invalid block size ===
776
777
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}}
778
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}}
779
{"return": {}}
780
Job failed: Block size must be a multiple of 1 MB
781
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
782
{"return": {}}
783
784
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}}
785
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}}
786
{"return": {}}
787
Job failed: Block size must be a multiple of 1 MB
788
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
789
{"return": {}}
790
791
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}}
792
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}}
793
{"return": {}}
794
Job failed: Block size must be a power of two
795
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
796
{"return": {}}
797
798
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}}
799
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}}
800
{"return": {}}
801
Job failed: Block size must not exceed 268435456
802
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
803
{"return": {}}
804
805
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}}
806
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}}
807
{"return": {}}
808
Job failed: Block size must be a multiple of 1 MB
809
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
810
@@ -XXX,XX +XXX,XX @@ Job failed: Block size must be a multiple of 1 MB
811
812
=== Invalid log size ===
813
814
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}}
815
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}}
816
{"return": {}}
817
Job failed: Log size must be a multiple of 1 MB
818
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
819
{"return": {}}
820
821
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}}
822
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}}
823
{"return": {}}
824
Job failed: Log size must be a multiple of 1 MB
825
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
826
{"return": {}}
827
828
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}}
829
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}}
830
{"return": {}}
831
Job failed: Log size must be smaller than 4 GB
832
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
833
{"return": {}}
834
835
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}}
836
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}}
837
{"return": {}}
838
Job failed: Log size must be a multiple of 1 MB
839
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
840
diff --git a/tests/qemu-iotests/237.out b/tests/qemu-iotests/237.out
841
index XXXXXXX..XXXXXXX 100644
842
--- a/tests/qemu-iotests/237.out
843
+++ b/tests/qemu-iotests/237.out
844
@@ -XXX,XX +XXX,XX @@
845
=== Successful image creation (defaults) ===
846
847
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
848
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
849
{"return": {}}
850
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
851
{"return": {}}
852
853
-{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node_name": "imgfile"}}
854
+{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node-name": "imgfile"}}
855
{"return": {}}
856
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}}
857
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}}
858
{"return": {}}
859
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
860
{"return": {}}
861
@@ -XXX,XX +XXX,XX @@ Format specific information:
862
863
=== Successful image creation (inline blockdev-add, explicit defaults) ===
864
865
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
866
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
867
{"return": {}}
868
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
869
{"return": {}}
870
871
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}}
872
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}}
873
{"return": {}}
874
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
875
{"return": {}}
876
@@ -XXX,XX +XXX,XX @@ Format specific information:
877
878
=== Successful image creation (with non-default options) ===
879
880
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
881
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
882
{"return": {}}
883
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
884
{"return": {}}
885
886
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}}
887
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}}
888
{"return": {}}
889
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
890
{"return": {}}
891
@@ -XXX,XX +XXX,XX @@ Format specific information:
892
893
=== Invalid BlockdevRef ===
894
895
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}}
896
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}}
897
{"return": {}}
898
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
899
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
900
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
901
902
== Valid adapter types ==
903
904
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}}
905
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}}
906
{"return": {}}
907
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
908
{"return": {}}
909
910
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}}
911
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}}
912
{"return": {}}
913
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
914
{"return": {}}
915
916
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}}
917
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}}
918
{"return": {}}
919
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
920
{"return": {}}
921
922
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}}
923
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}}
924
{"return": {}}
925
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
926
{"return": {}}
927
928
== Invalid adapter types ==
929
930
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}}
931
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}}
932
{"error": {"class": "GenericError", "desc": "Invalid parameter 'foo'"}}
933
934
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}}
935
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}}
936
{"error": {"class": "GenericError", "desc": "Invalid parameter 'IDE'"}}
937
938
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}}
939
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}}
940
{"error": {"class": "GenericError", "desc": "Invalid parameter 'legacyesx'"}}
941
942
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}}
943
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}}
944
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'options.adapter-type', expected: string"}}
945
946
=== Other subformats ===
947
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefi
948
949
== Missing extent ==
950
951
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}}
952
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}}
953
{"return": {}}
954
Job failed: Extent [0] not specified
955
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
956
@@ -XXX,XX +XXX,XX @@ Job failed: Extent [0] not specified
957
958
== Correct extent ==
959
960
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}}
961
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}}
962
{"return": {}}
963
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
964
{"return": {}}
965
966
== Extra extent ==
967
968
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}}
969
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}}
970
{"return": {}}
971
Job failed: List of extents contains unused extents
972
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
973
@@ -XXX,XX +XXX,XX @@ Job failed: List of extents contains unused extents
974
975
= twoGbMaxExtentFlat 512 =
976
977
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}}
978
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}}
979
{"return": {}}
980
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
981
{"return": {}}
982
@@ -XXX,XX +XXX,XX @@ Format specific information:
983
984
= twoGbMaxExtentSparse 512 =
985
986
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}}
987
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}}
988
{"return": {}}
989
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
990
{"return": {}}
991
@@ -XXX,XX +XXX,XX @@ Format specific information:
992
993
= twoGbMaxExtentFlat 1073741824 =
994
995
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}}
996
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}}
997
{"return": {}}
998
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
999
{"return": {}}
1000
@@ -XXX,XX +XXX,XX @@ Format specific information:
1001
1002
= twoGbMaxExtentSparse 1073741824 =
1003
1004
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}}
1005
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}}
1006
{"return": {}}
1007
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1008
{"return": {}}
1009
@@ -XXX,XX +XXX,XX @@ Format specific information:
1010
1011
= twoGbMaxExtentFlat 2147483648 =
1012
1013
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}}
1014
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}}
1015
{"return": {}}
1016
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1017
{"return": {}}
1018
@@ -XXX,XX +XXX,XX @@ Format specific information:
1019
1020
= twoGbMaxExtentSparse 2147483648 =
1021
1022
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}}
1023
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}}
1024
{"return": {}}
1025
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1026
{"return": {}}
1027
@@ -XXX,XX +XXX,XX @@ Format specific information:
1028
1029
= twoGbMaxExtentFlat 5368709120 =
1030
1031
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}}
1032
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}}
1033
{"return": {}}
1034
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1035
{"return": {}}
1036
@@ -XXX,XX +XXX,XX @@ Format specific information:
1037
1038
= twoGbMaxExtentSparse 5368709120 =
1039
1040
-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}}
1041
+{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}}
1042
{"return": {}}
1043
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1044
{"return": {}}
1045
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
1046
index XXXXXXX..XXXXXXX 100644
1047
--- a/tests/qemu-iotests/iotests.py
1048
+++ b/tests/qemu-iotests/iotests.py
1049
@@ -XXX,XX +XXX,XX @@ def qemu_img(*args):
1050
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
1051
return exitcode
1052
1053
-def ordered_qmp(qmsg):
1054
+def ordered_qmp(qmsg, conv_keys=True):
1055
# Dictionaries are not ordered prior to 3.6, therefore:
1056
if isinstance(qmsg, list):
1057
return [ordered_qmp(atom) for atom in qmsg]
1058
if isinstance(qmsg, dict):
1059
od = OrderedDict()
1060
for k, v in sorted(qmsg.items()):
1061
- od[k] = ordered_qmp(v)
1062
+ if conv_keys:
1063
+ k = k.replace('_', '-')
1064
+ od[k] = ordered_qmp(v, conv_keys=False)
1065
return od
1066
return qmsg
1067
1068
--
1069
2.20.1
1070
1071
diff view generated by jsdifflib
Deleted patch
1
From: yuchenlin <yuchenlin@synology.com>
2
1
3
In vmdk_co_create_opts, when it finds hw_version is undefined, it will
4
set it to 4, which misleading the compat6 and hwversion in
5
vmdk_co_do_create. Simply set hw_version to NULL after free, let
6
the logic in vmdk_co_do_create to decide the value of hw_version.
7
8
This bug can be reproduced by:
9
10
$ qemu-img convert -O vmdk -o subformat=streamOptimized,compat6
11
/home/yuchenlin/syno.qcow2 /home/yuchenlin/syno.vmdk
12
13
qemu-img: /home/yuchenlin/syno.vmdk: error while converting vmdk:
14
compat6 cannot be enabled with hwversion set
15
16
Signed-off-by: yuchenlin <yuchenlin@synology.com>
17
Message-id: 20190221110805.28239-1-yuchenlin@synology.com
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
block/vmdk.c | 2 +-
21
1 file changed, 1 insertion(+), 1 deletion(-)
22
23
diff --git a/block/vmdk.c b/block/vmdk.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/vmdk.c
26
+++ b/block/vmdk.c
27
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts
28
compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false);
29
if (strcmp(hw_version, "undefined") == 0) {
30
g_free(hw_version);
31
- hw_version = g_strdup("4");
32
+ hw_version = NULL;
33
}
34
fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
35
zeroed_grain = qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false);
36
--
37
2.20.1
38
39
diff view generated by jsdifflib