1
The following changes since commit 63f495beb4007de5444614125fd6fd178ca6e2b1:
1
The following changes since commit 91fe7a376ad46e3cc5e82d418aad22173c948a3c:
2
2
3
Merge remote-tracking branch 'remotes/kraxel/tags/pull-cve-2017-2620-20170224-1' into staging (2017-02-24 13:55:26 +0000)
3
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging (2018-06-15 11:41:44 +0100)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
8
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
9
8
10
for you to fetch changes up to d185cf0ec64cd183218ca7e0810d9130c96ebebc:
9
for you to fetch changes up to 6266e900b8083945cb766b45c124fb3c42932cb3:
11
10
12
tests: Use opened block node for block job tests (2017-02-24 16:09:23 +0100)
11
block: Remove dead deprecation warning code (2018-06-15 14:49:44 +0200)
13
12
14
----------------------------------------------------------------
13
----------------------------------------------------------------
15
Block layer patches
14
Block layer patches:
15
16
- Fix options that work only with -drive or -blockdev, but not with
17
both, because of QDict type confusion
18
- rbd: Add options 'auth-client-required' and 'key-secret'
19
- Remove deprecated -drive options serial/addr/cyls/heads/secs/trans
20
- rbd, iscsi: Remove deprecated 'filename' option
21
- Fix 'qemu-img map' crash with unaligned image size
22
- Improve QMP documentation for jobs
16
23
17
----------------------------------------------------------------
24
----------------------------------------------------------------
18
Jeff Cody (3):
25
Eric Blake (2):
19
qemu-iotests: Test 137 only supports 'file' protocol
26
qemu-img: Fix assert when mapping unaligned raw file
20
qemu-iotests: add ability to exclude certain protocols from tests
27
iotests: Add test 221 to catch qemu-img map regression
21
qemu-iotests: redirect nbd server stdout to /dev/null
22
28
23
John Snow (1):
29
John Snow (2):
24
iotests: Fix another race in 030
30
jobs: fix stale wording
31
jobs: fix verb references in docs
25
32
26
Kevin Wolf (11):
33
Kevin Wolf (4):
27
blockdev: Use BlockBackend to resize in qmp_block_resize()
34
block: Remove deprecated -drive geometry options
28
qcow2: Use BB for resizing in qcow2_amend_options()
35
block: Remove deprecated -drive option addr
29
mirror: Resize active commit base in mirror_run()
36
block: Remove deprecated -drive option serial
30
block: Pass BdrvChild to bdrv_truncate()
37
block: Remove dead deprecation warning code
31
block: Attach bs->file only during .bdrv_open()
32
block: Factor out bdrv_open_child_bs()
33
block: Use BlockBackend for image probing
34
block: Factor out bdrv_open_driver()
35
block: Add bdrv_new_open_driver()
36
vvfat: Use opened node as backing file
37
tests: Use opened block node for block job tests
38
38
39
Nir Soffer (4):
39
Markus Armbruster (17):
40
qemu-img: Do not truncate before preallocation
40
rbd: Drop deprecated -drive parameter "filename"
41
qemu-img: Add tests for raw image preallocation
41
iscsi: Drop deprecated -drive parameter "filename"
42
qemu-img: Truncate before full preallocation
42
qobject: Move block-specific qdict code to block-qdict.c
43
qemu-img: Improve documentation for PREALLOC_MODE_FALLOC
43
block: Fix -blockdev for certain non-string scalars
44
block: Fix -drive for certain non-string scalars
45
block: Clean up a misuse of qobject_to() in .bdrv_co_create_opts()
46
block: Factor out qobject_input_visitor_new_flat_confused()
47
block: Make remaining uses of qobject input visitor more robust
48
block-qdict: Simplify qdict_flatten_qdict()
49
block-qdict: Tweak qdict_flatten_qdict(), qdict_flatten_qlist()
50
block-qdict: Clean up qdict_crumple() a bit
51
block-qdict: Simplify qdict_is_list() some
52
check-block-qdict: Rename qdict_flatten()'s variables for clarity
53
check-block-qdict: Cover flattening of empty lists and dictionaries
54
block: Fix -blockdev / blockdev-add for empty objects and arrays
55
rbd: New parameter auth-client-required
56
rbd: New parameter key-secret
44
57
45
block.c | 265 +++++++++++++++++++++++++++---------------
58
Max Reitz (1):
46
block/blkdebug.c | 2 +-
59
block: Add block-specific QDict header
47
block/block-backend.c | 2 +-
48
block/bochs.c | 6 +
49
block/cloop.c | 6 +
50
block/crypto.c | 8 +-
51
block/dmg.c | 6 +
52
block/file-posix.c | 28 +++--
53
block/mirror.c | 50 ++++----
54
block/parallels.c | 14 ++-
55
block/qcow.c | 10 +-
56
block/qcow2-refcount.c | 2 +-
57
block/qcow2.c | 28 ++++-
58
block/qed.c | 18 ++-
59
block/raw-format.c | 8 +-
60
block/replication.c | 6 +
61
block/vdi.c | 6 +
62
block/vhdx-log.c | 2 +-
63
block/vhdx.c | 8 +-
64
block/vmdk.c | 6 +
65
block/vpc.c | 6 +
66
block/vvfat.c | 10 +-
67
blockdev.c | 7 +-
68
include/block/block.h | 4 +-
69
tests/qemu-iotests/030 | 5 +-
70
tests/qemu-iotests/051.out | 4 +-
71
tests/qemu-iotests/051.pc.out | 4 +-
72
tests/qemu-iotests/137 | 2 +-
73
tests/qemu-iotests/175 | 61 ++++++++++
74
tests/qemu-iotests/175.out | 18 +++
75
tests/qemu-iotests/common.rc | 14 ++-
76
tests/qemu-iotests/group | 1 +
77
tests/test-blockjob-txn.c | 6 +-
78
tests/test-blockjob.c | 6 +-
79
34 files changed, 461 insertions(+), 168 deletions(-)
80
create mode 100755 tests/qemu-iotests/175
81
create mode 100644 tests/qemu-iotests/175.out
82
60
61
qapi/block-core.json | 19 ++
62
qapi/job.json | 23 +-
63
include/block/qdict.h | 34 +++
64
include/hw/block/block.h | 1 -
65
include/qapi/qmp/qdict.h | 17 --
66
include/sysemu/blockdev.h | 3 -
67
block.c | 1 +
68
block/block-backend.c | 1 -
69
block/crypto.c | 12 +-
70
block/gluster.c | 1 +
71
block/iscsi.c | 24 +-
72
block/nbd.c | 16 +-
73
block/nfs.c | 8 +-
74
block/parallels.c | 11 +-
75
block/qcow.c | 11 +-
76
block/qcow2.c | 11 +-
77
block/qed.c | 11 +-
78
block/quorum.c | 1 +
79
block/rbd.c | 85 +++---
80
block/sheepdog.c | 23 +-
81
block/snapshot.c | 1 +
82
block/ssh.c | 16 +-
83
block/vdi.c | 8 +-
84
block/vhdx.c | 11 +-
85
block/vpc.c | 11 +-
86
block/vvfat.c | 1 +
87
block/vxhs.c | 1 +
88
blockdev.c | 111 +------
89
device-hotplug.c | 4 -
90
hw/block/block.c | 27 --
91
hw/block/nvme.c | 1 -
92
hw/block/virtio-blk.c | 1 -
93
hw/ide/qdev.c | 1 -
94
hw/scsi/scsi-disk.c | 1 -
95
hw/usb/dev-storage.c | 1 -
96
qemu-img.c | 2 +-
97
qobject/block-qdict.c | 722 +++++++++++++++++++++++++++++++++++++++++++++
98
qobject/qdict.c | 628 ---------------------------------------
99
tests/ahci-test.c | 6 +-
100
tests/check-block-qdict.c | 690 +++++++++++++++++++++++++++++++++++++++++++
101
tests/check-qdict.c | 641 ----------------------------------------
102
tests/check-qobject.c | 1 +
103
tests/hd-geo-test.c | 37 +--
104
tests/ide-test.c | 8 +-
105
tests/test-replication.c | 1 +
106
util/qemu-config.c | 1 +
107
MAINTAINERS | 2 +
108
hmp-commands.hx | 1 -
109
qemu-doc.texi | 15 -
110
qemu-options.hx | 14 +-
111
qobject/Makefile.objs | 1 +
112
tests/Makefile.include | 4 +
113
tests/qemu-iotests/221 | 60 ++++
114
tests/qemu-iotests/221.out | 16 +
115
tests/qemu-iotests/group | 1 +
116
55 files changed, 1692 insertions(+), 1668 deletions(-)
117
create mode 100644 include/block/qdict.h
118
create mode 100644 qobject/block-qdict.c
119
create mode 100644 tests/check-block-qdict.c
120
create mode 100755 tests/qemu-iotests/221
121
create mode 100644 tests/qemu-iotests/221.out
122
diff view generated by jsdifflib
New patch
1
From: Eric Blake <eblake@redhat.com>
1
2
3
Commit a290f085 exposed a latent bug in qemu-img map introduced
4
during the conversion of block status to be byte-based. Earlier in
5
commit 5e344dd8, the internal interface get_block_status() switched
6
to take byte-based parameters, but still called a sector-based
7
block layer function; as such, rounding was added in the lone
8
caller to obey the contract. However, commit 237d78f8 changed
9
get_block_status() to truly be byte-based, at which point rounding
10
to sector boundaries can result in calling bdrv_block_status() with
11
'bytes == 0' (a coding error) when the boundary between data and a
12
hole falls mid-sector (true for the past-EOF implicit hole present
13
in POSIX files). Fix things by removing the rounding that is now
14
no longer necessary.
15
16
See also https://bugzilla.redhat.com/1589738
17
18
Fixes: 237d78f8
19
Reported-by: Dan Kenigsberg <danken@redhat.com>
20
Reported-by: Nir Soffer <nsoffer@redhat.com>
21
Reported-by: Maor Lipchuk <mlipchuk@redhat.com>
22
CC: qemu-stable@nongnu.org
23
Signed-off-by: Eric Blake <eblake@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
26
qemu-img.c | 2 +-
27
1 file changed, 1 insertion(+), 1 deletion(-)
28
29
diff --git a/qemu-img.c b/qemu-img.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/qemu-img.c
32
+++ b/qemu-img.c
33
@@ -XXX,XX +XXX,XX @@ static int img_map(int argc, char **argv)
34
int64_t n;
35
36
/* Probe up to 1 GiB at a time. */
37
- n = QEMU_ALIGN_DOWN(MIN(1 << 30, length - offset), BDRV_SECTOR_SIZE);
38
+ n = MIN(1 << 30, length - offset);
39
ret = get_block_status(bs, offset, n, &next);
40
41
if (ret < 0) {
42
--
43
2.13.6
44
45
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Add tests for creating raw image with and without the preallocation
3
Although qemu-img creates aligned files (by rounding up), it
4
option.
4
must also gracefully handle files that are not sector-aligned.
5
Test that the bug fixed in the previous patch does not recur.
5
6
6
Signed-off-by: Nir Soffer <nirsof@gmail.com>
7
It's a bit annoying that we can see the (implicit) hole past
8
the end of the file on to the next sector boundary, so if we
9
ever reach the point where we report a byte-accurate size rather
10
than our current behavior of always rounding up, this test will
11
probably need a slight modification.
12
13
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
15
---
9
tests/qemu-iotests/175 | 61 ++++++++++++++++++++++++++++++++++++++++++++++
16
tests/qemu-iotests/221 | 60 ++++++++++++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/175.out | 18 ++++++++++++++
17
tests/qemu-iotests/221.out | 16 +++++++++++++
11
tests/qemu-iotests/group | 1 +
18
tests/qemu-iotests/group | 1 +
12
3 files changed, 80 insertions(+)
19
3 files changed, 77 insertions(+)
13
create mode 100755 tests/qemu-iotests/175
20
create mode 100755 tests/qemu-iotests/221
14
create mode 100644 tests/qemu-iotests/175.out
21
create mode 100644 tests/qemu-iotests/221.out
15
22
16
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
23
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
17
new file mode 100755
24
new file mode 100755
18
index XXXXXXX..XXXXXXX
25
index XXXXXXX..XXXXXXX
19
--- /dev/null
26
--- /dev/null
20
+++ b/tests/qemu-iotests/175
27
+++ b/tests/qemu-iotests/221
21
@@ -XXX,XX +XXX,XX @@
28
@@ -XXX,XX +XXX,XX @@
22
+#!/bin/bash
29
+#!/bin/bash
23
+#
30
+#
24
+# Test creating raw image preallocation mode
31
+# Test qemu-img vs. unaligned images
25
+#
32
+#
26
+# Copyright (C) 2017 Nir Soffer <nirsof@gmail.com>
33
+# Copyright (C) 2018 Red Hat, Inc.
27
+#
34
+#
28
+# This program is free software; you can redistribute it and/or modify
35
+# This program is free software; you can redistribute it and/or modify
29
+# it under the terms of the GNU General Public License as published by
36
+# it under the terms of the GNU General Public License as published by
30
+# the Free Software Foundation; either version 2 of the License, or
37
+# the Free Software Foundation; either version 2 of the License, or
31
+# (at your option) any later version.
38
+# (at your option) any later version.
...
...
37
+#
44
+#
38
+# You should have received a copy of the GNU General Public License
45
+# You should have received a copy of the GNU General Public License
39
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
46
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
40
+#
47
+#
41
+
48
+
42
+# creator
49
+seq="$(basename $0)"
43
+owner=nirsof@gmail.com
44
+
45
+seq=`basename $0`
46
+echo "QA output created by $seq"
50
+echo "QA output created by $seq"
47
+
51
+
48
+here=`pwd`
52
+here="$PWD"
49
+status=1    # failure is the default!
53
+status=1 # failure is the default!
50
+
54
+
51
+_cleanup()
55
+_cleanup()
52
+{
56
+{
53
+    _cleanup_test_img
57
+ _cleanup_test_img
54
+}
58
+}
55
+trap "_cleanup; exit \$status" 0 1 2 3 15
59
+trap "_cleanup; exit \$status" 0 1 2 3 15
56
+
60
+
57
+# get standard environment, filters and checks
61
+# get standard environment, filters and checks
58
+. ./common.rc
62
+. ./common.rc
59
+. ./common.filter
63
+. ./common.filter
60
+
64
+
61
+_supported_fmt raw
65
+_supported_fmt raw
62
+_supported_proto file
66
+_supported_proto file
63
+_supported_os Linux
67
+_supported_os Linux
64
+
68
+
65
+size=1m
69
+echo
70
+echo "=== Check mapping of unaligned raw image ==="
71
+echo
66
+
72
+
67
+echo
73
+_make_test_img 43009 # qemu-img create rounds size up
68
+echo "== creating image with default preallocation =="
74
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
69
+_make_test_img $size | _filter_imgfmt
70
+stat -c "size=%s, blocks=%b" $TEST_IMG
71
+
75
+
72
+for mode in off full falloc; do
76
+truncate --size=43009 "$TEST_IMG" # so we resize it and check again
73
+ echo
77
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
74
+ echo "== creating image with preallocation $mode =="
78
+
75
+ IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
79
+$QEMU_IO -c 'w 43008 1' "$TEST_IMG" | _filter_qemu_io # writing also rounds up
76
+ stat -c "size=%s, blocks=%b" $TEST_IMG
80
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
77
+done
81
+
82
+truncate --size=43009 "$TEST_IMG" # so we resize it and check again
83
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
78
+
84
+
79
+# success, all done
85
+# success, all done
80
+echo "*** done"
86
+echo '*** done'
81
+rm -f $seq.full
87
+rm -f $seq.full
82
+status=0
88
+status=0
83
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
89
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
84
new file mode 100644
90
new file mode 100644
85
index XXXXXXX..XXXXXXX
91
index XXXXXXX..XXXXXXX
86
--- /dev/null
92
--- /dev/null
87
+++ b/tests/qemu-iotests/175.out
93
+++ b/tests/qemu-iotests/221.out
88
@@ -XXX,XX +XXX,XX @@
94
@@ -XXX,XX +XXX,XX @@
89
+QA output created by 175
95
+QA output created by 221
90
+
96
+
91
+== creating image with default preallocation ==
97
+=== Check mapping of unaligned raw image ===
92
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
93
+size=1048576, blocks=0
94
+
98
+
95
+== creating image with preallocation off ==
99
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=43009
96
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off
100
+[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
97
+size=1048576, blocks=0
101
+[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
98
+
102
+wrote 1/1 bytes at offset 43008
99
+== creating image with preallocation full ==
103
+1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
100
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full
104
+[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
101
+size=1048576, blocks=2048
105
+{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
102
+
106
+{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
103
+== creating image with preallocation falloc ==
107
+[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
104
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
108
+{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
105
+size=1048576, blocks=2048
109
+{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
106
+ *** done
110
+*** done
107
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
111
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
108
index XXXXXXX..XXXXXXX 100644
112
index XXXXXXX..XXXXXXX 100644
109
--- a/tests/qemu-iotests/group
113
--- a/tests/qemu-iotests/group
110
+++ b/tests/qemu-iotests/group
114
+++ b/tests/qemu-iotests/group
111
@@ -XXX,XX +XXX,XX @@
115
@@ -XXX,XX +XXX,XX @@
112
172 auto
116
217 rw auto quick
113
173 rw auto
117
218 rw auto quick
114
174 auto
118
219 rw auto
115
+175 auto quick
119
+221 rw auto quick
116
--
120
--
117
1.8.3.1
121
2.13.6
118
122
119
123
diff view generated by jsdifflib
New patch
1
From: John Snow <jsnow@redhat.com>
1
2
3
During the design for manual completion, we decided not to use the
4
"manual" property as a shorthand for both auto-dismiss and auto-finalize.
5
6
Fix the wording.
7
8
Signed-off-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
qapi/job.json | 11 ++++++-----
14
1 file changed, 6 insertions(+), 5 deletions(-)
15
16
diff --git a/qapi/job.json b/qapi/job.json
17
index XXXXXXX..XXXXXXX 100644
18
--- a/qapi/job.json
19
+++ b/qapi/job.json
20
@@ -XXX,XX +XXX,XX @@
21
# the last job in a transaction.
22
#
23
# @pending: The job has finished its work, but has finalization steps that it
24
-# needs to make prior to completing. These changes may require
25
-# manual intervention by the management process if manual was set
26
-# to true. These changes may still fail.
27
+# needs to make prior to completing. These changes will require
28
+# manual intervention via @job-finalize if auto-finalize was set to
29
+# false. These pending changes may still fail.
30
#
31
# @aborting: The job is in the process of being aborted, and will finish with
32
# an error. The job will afterwards report that it is @concluded.
33
# This status may not be visible to the management process.
34
#
35
-# @concluded: The job has finished all work. If manual was set to true, the job
36
-# will remain in the query list until it is dismissed.
37
+# @concluded: The job has finished all work. If auto-dismiss was set to false,
38
+# the job will remain in the query list until it is dismissed via
39
+# @job-dismiss.
40
#
41
# @null: The job is in the process of being dismantled. This state should not
42
# ever be visible externally.
43
--
44
2.13.6
45
46
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: John Snow <jsnow@redhat.com>
2
2
3
We can't rely on a non-paused job to be present and running for us.
3
These point to the job versions now, not the blockjob versions which
4
Assume that if the job is not present that it completed already.
4
don't really exist anymore.
5
6
Except set-speed, which does. It sticks out like a sore thumb. This
7
patch doesn't fix that, but it doesn't make it any worse, either.
5
8
6
Signed-off-by: John Snow <jsnow@redhat.com>
9
Signed-off-by: John Snow <jsnow@redhat.com>
7
Reviewed-by: Fam Zheng <famz@redhat.com>
10
Reviewed-by: Jeff Cody <jcody@redhat.com>
11
Reviewed-by: Markus Armbruster <armbru@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
13
---
10
tests/qemu-iotests/030 | 5 ++++-
14
qapi/job.json | 12 ++++++------
11
1 file changed, 4 insertions(+), 1 deletion(-)
15
1 file changed, 6 insertions(+), 6 deletions(-)
12
16
13
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
17
diff --git a/qapi/job.json b/qapi/job.json
14
index XXXXXXX..XXXXXXX 100755
18
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/030
19
--- a/qapi/job.json
16
+++ b/tests/qemu-iotests/030
20
+++ b/qapi/job.json
17
@@ -XXX,XX +XXX,XX @@ class TestEIO(TestErrors):
21
@@ -XXX,XX +XXX,XX @@
18
while not completed:
22
#
19
for event in self.vm.get_qmp_events(wait=True):
23
# Represents command verbs that can be applied to a job.
20
if event['event'] == 'BLOCK_JOB_ERROR':
24
#
21
+ error = True
25
-# @cancel: see @block-job-cancel
22
self.assert_qmp(event, 'data/device', 'drive0')
26
+# @cancel: see @job-cancel
23
self.assert_qmp(event, 'data/operation', 'read')
27
#
24
result = self.vm.qmp('query-block-jobs')
28
-# @pause: see @block-job-pause
25
+ if result == {'return': []}:
29
+# @pause: see @job-pause
26
+ # Job finished too quickly
30
#
27
+ continue
31
-# @resume: see @block-job-resume
28
self.assert_qmp(result, 'return[0]/paused', False)
32
+# @resume: see @job-resume
29
- error = True
33
#
30
elif event['event'] == 'BLOCK_JOB_COMPLETED':
34
# @set-speed: see @block-job-set-speed
31
self.assertTrue(error, 'job completed unexpectedly')
35
#
32
self.assert_qmp(event, 'data/type', 'stream')
36
-# @complete: see @block-job-complete
37
+# @complete: see @job-complete
38
#
39
-# @dismiss: see @block-job-dismiss
40
+# @dismiss: see @job-dismiss
41
#
42
-# @finalize: see @block-job-finalize
43
+# @finalize: see @job-finalize
44
#
45
# Since: 2.12
46
##
33
--
47
--
34
1.8.3.1
48
2.13.6
35
49
36
50
diff view generated by jsdifflib
New patch
1
From: Markus Armbruster <armbru@redhat.com>
1
2
3
Parameter "filename" is deprecated since commit 91589d9e5ca, v2.10.0.
4
Time to get rid of it.
5
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
block/rbd.c | 16 ----------------
11
1 file changed, 16 deletions(-)
12
13
diff --git a/block/rbd.c b/block/rbd.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/rbd.c
16
+++ b/block/rbd.c
17
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
18
QObject *crumpled = NULL;
19
const QDictEntry *e;
20
Error *local_err = NULL;
21
- const char *filename;
22
char *keypairs, *secretid;
23
int r;
24
25
- /* If we are given a filename, parse the filename, with precedence given to
26
- * filename encoded options */
27
- filename = qdict_get_try_str(options, "filename");
28
- if (filename) {
29
- warn_report("'filename' option specified. "
30
- "This is an unsupported option, and may be deprecated "
31
- "in the future");
32
- qemu_rbd_parse_filename(filename, options, &local_err);
33
- qdict_del(options, "filename");
34
- if (local_err) {
35
- error_propagate(errp, local_err);
36
- return -EINVAL;
37
- }
38
- }
39
-
40
keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
41
if (keypairs) {
42
qdict_del(options, "=keyvalue-pairs");
43
--
44
2.13.6
45
46
diff view generated by jsdifflib
1
blk_insert_bs() and block job related functions will soon require an
1
From: Markus Armbruster <armbru@redhat.com>
2
opened block node (permission calculations will involve the block
3
driver), so let our tests be consistent with the real users in this
4
respect.
5
2
3
Parameter "filename" is deprecated since commit 5c3ad1a6a8f, v2.10.0.
4
Time to get rid of it.
5
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
---
9
tests/test-blockjob-txn.c | 6 +++++-
10
block/iscsi.c | 23 ++---------------------
10
tests/test-blockjob.c | 6 +++++-
11
1 file changed, 2 insertions(+), 21 deletions(-)
11
2 files changed, 10 insertions(+), 2 deletions(-)
12
12
13
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
13
diff --git a/block/iscsi.c b/block/iscsi.c
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/test-blockjob-txn.c
15
--- a/block/iscsi.c
16
+++ b/tests/test-blockjob-txn.c
16
+++ b/block/iscsi.c
17
@@ -XXX,XX +XXX,XX @@ static BlockJob *test_block_job_start(unsigned int iterations,
17
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
18
char job_id[24];
18
.name = "timeout",
19
19
.type = QEMU_OPT_NUMBER,
20
data = g_new0(TestBlockJobCBData, 1);
20
},
21
- bs = bdrv_new();
21
- {
22
- .name = "filename",
23
- .type = QEMU_OPT_STRING,
24
- },
25
{ /* end of list */ }
26
},
27
};
28
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
29
char *initiator_name = NULL;
30
QemuOpts *opts;
31
Error *local_err = NULL;
32
- const char *transport_name, *portal, *target, *filename;
33
+ const char *transport_name, *portal, *target;
34
#if LIBISCSI_API_VERSION >= (20160603)
35
enum iscsi_transport_type transport;
36
#endif
37
int i, ret = 0, timeout = 0, lun;
38
39
- /* If we are given a filename, parse the filename, with precedence given to
40
- * filename encoded options */
41
- filename = qdict_get_try_str(options, "filename");
42
- if (filename) {
43
- warn_report("'filename' option specified. "
44
- "This is an unsupported option, and may be deprecated "
45
- "in the future");
46
- iscsi_parse_filename(filename, options, &local_err);
47
- if (local_err) {
48
- ret = -EINVAL;
49
- error_propagate(errp, local_err);
50
- goto exit;
51
- }
52
- }
53
-
54
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
55
qemu_opts_absorb_qdict(opts, options, &local_err);
56
if (local_err) {
57
@@ -XXX,XX +XXX,XX @@ out:
58
}
59
memset(iscsilun, 0, sizeof(IscsiLun));
60
}
61
-exit:
22
+
62
+
23
+ bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
63
return ret;
24
+ g_assert_nonnull(bs);
64
}
25
+
65
26
snprintf(job_id, sizeof(job_id), "job%u", counter++);
27
s = block_job_create(job_id, &test_block_job_driver, bs, 0,
28
BLOCK_JOB_DEFAULT, test_block_job_cb,
29
@@ -XXX,XX +XXX,XX @@ static void test_pair_jobs_fail_cancel_race(void)
30
int main(int argc, char **argv)
31
{
32
qemu_init_main_loop(&error_abort);
33
+ bdrv_init();
34
35
g_test_init(&argc, &argv, NULL);
36
g_test_add_func("/single/success", test_single_job_success);
37
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/tests/test-blockjob.c
40
+++ b/tests/test-blockjob.c
41
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
42
static BlockBackend *create_blk(const char *name)
43
{
44
BlockBackend *blk = blk_new();
45
- BlockDriverState *bs = bdrv_new();
46
+ BlockDriverState *bs;
47
+
48
+ bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
49
+ g_assert_nonnull(bs);
50
51
blk_insert_bs(blk, bs);
52
bdrv_unref(bs);
53
@@ -XXX,XX +XXX,XX @@ static void test_job_ids(void)
54
int main(int argc, char **argv)
55
{
56
qemu_init_main_loop(&error_abort);
57
+ bdrv_init();
58
59
g_test_init(&argc, &argv, NULL);
60
g_test_add_func("/blockjob/ids", test_job_ids);
61
--
66
--
62
1.8.3.1
67
2.13.6
63
68
64
69
diff view generated by jsdifflib
1
The way that attaching bs->file worked was a bit unusual in that it was
1
From: Max Reitz <mreitz@redhat.com>
2
the only child that would be attached to a node which is not opened yet.
2
3
Because of this, the block layer couldn't know yet which permissions the
3
There are numerous QDict functions that have been introduced for and are
4
driver would eventually need.
4
used only by the block layer. Move their declarations into an own
5
5
header file to reflect that.
6
This patch moves the point where bs->file is attached to the beginning
6
7
of the individual .bdrv_open() implementations, so drivers already know
7
While qdict_extract_subqdict() is in fact used outside of the block
8
what they are going to do with the child. This is also more consistent
8
layer (in util/qemu-config.c), it is still a function related very
9
with how driver-specific children work.
9
closely to how the block layer works with nested QDicts, namely by
10
10
sometimes flattening them. Therefore, its declaration is put into this
11
For a moment, bdrv_open() gets its own BdrvChild to perform image
11
header as well and util/qemu-config.c includes it with a comment stating
12
probing, but instead of directly assigning this BdrvChild to the BDS, it
12
exactly which function it needs.
13
becomes a temporary one and the node name is passed as an option to the
13
14
drivers, so that they can simply use bdrv_open_child() to create another
14
Suggested-by: Markus Armbruster <armbru@redhat.com>
15
reference for their own use.
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
16
Message-Id: <20180509165530.29561-7-mreitz@redhat.com>
17
This duplicated child for (the not opened yet) bs is not the final
17
[Copyright note tweaked, superfluous includes dropped]
18
state, a follow-up patch will change the image probing code to use a
18
Signed-off-by: Markus Armbruster <armbru@redhat.com>
19
BlockBackend, which is completely independent of bs.
19
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
20
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Reviewed-by: Max Reitz <mreitz@redhat.com>
23
---
21
---
24
block.c | 35 ++++++++++++++++++++++++-----------
22
include/block/qdict.h | 32 ++++++++++++++++++++++++++++++++
25
block/bochs.c | 6 ++++++
23
include/qapi/qmp/qdict.h | 17 -----------------
26
block/cloop.c | 6 ++++++
24
block.c | 1 +
27
block/crypto.c | 6 ++++++
25
block/gluster.c | 1 +
28
block/dmg.c | 6 ++++++
26
block/iscsi.c | 1 +
29
block/parallels.c | 6 ++++++
27
block/nbd.c | 1 +
30
block/qcow.c | 6 ++++++
28
block/nfs.c | 1 +
31
block/qcow2.c | 18 +++++++++++++++---
29
block/parallels.c | 1 +
32
block/qed.c | 18 +++++++++++++++---
30
block/qcow.c | 1 +
33
block/raw-format.c | 6 ++++++
31
block/qcow2.c | 1 +
34
block/replication.c | 6 ++++++
32
block/qed.c | 1 +
35
block/vdi.c | 6 ++++++
33
block/quorum.c | 1 +
36
block/vhdx.c | 6 ++++++
34
block/rbd.c | 1 +
37
block/vmdk.c | 6 ++++++
35
block/sheepdog.c | 1 +
38
block/vpc.c | 6 ++++++
36
block/snapshot.c | 1 +
39
tests/qemu-iotests/051.out | 4 ++--
37
block/ssh.c | 1 +
40
tests/qemu-iotests/051.pc.out | 4 ++--
38
block/vhdx.c | 1 +
41
17 files changed, 130 insertions(+), 21 deletions(-)
39
block/vpc.c | 1 +
42
40
block/vvfat.c | 1 +
41
block/vxhs.c | 1 +
42
blockdev.c | 1 +
43
qobject/qdict.c | 1 +
44
tests/check-qdict.c | 1 +
45
tests/check-qobject.c | 1 +
46
tests/test-replication.c | 1 +
47
util/qemu-config.c | 1 +
48
26 files changed, 56 insertions(+), 17 deletions(-)
49
create mode 100644 include/block/qdict.h
50
51
diff --git a/include/block/qdict.h b/include/block/qdict.h
52
new file mode 100644
53
index XXXXXXX..XXXXXXX
54
--- /dev/null
55
+++ b/include/block/qdict.h
56
@@ -XXX,XX +XXX,XX @@
57
+/*
58
+ * Special QDict functions used by the block layer
59
+ *
60
+ * Copyright (c) 2013-2018 Red Hat, Inc.
61
+ *
62
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
63
+ * See the COPYING.LIB file in the top-level directory.
64
+ */
65
+
66
+#ifndef BLOCK_QDICT_H
67
+#define BLOCK_QDICT_H
68
+
69
+#include "qapi/qmp/qdict.h"
70
+
71
+void qdict_copy_default(QDict *dst, QDict *src, const char *key);
72
+void qdict_set_default_str(QDict *dst, const char *key, const char *val);
73
+
74
+void qdict_join(QDict *dest, QDict *src, bool overwrite);
75
+
76
+void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
77
+void qdict_array_split(QDict *src, QList **dst);
78
+int qdict_array_entries(QDict *src, const char *subqdict);
79
+QObject *qdict_crumple(const QDict *src, Error **errp);
80
+void qdict_flatten(QDict *qdict);
81
+
82
+typedef struct QDictRenames {
83
+ const char *from;
84
+ const char *to;
85
+} QDictRenames;
86
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
87
+
88
+#endif
89
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
90
index XXXXXXX..XXXXXXX 100644
91
--- a/include/qapi/qmp/qdict.h
92
+++ b/include/qapi/qmp/qdict.h
93
@@ -XXX,XX +XXX,XX @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key,
94
bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value);
95
const char *qdict_get_try_str(const QDict *qdict, const char *key);
96
97
-void qdict_copy_default(QDict *dst, QDict *src, const char *key);
98
-void qdict_set_default_str(QDict *dst, const char *key, const char *val);
99
-
100
QDict *qdict_clone_shallow(const QDict *src);
101
-void qdict_flatten(QDict *qdict);
102
-
103
-void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
104
-void qdict_array_split(QDict *src, QList **dst);
105
-int qdict_array_entries(QDict *src, const char *subqdict);
106
-QObject *qdict_crumple(const QDict *src, Error **errp);
107
-
108
-void qdict_join(QDict *dest, QDict *src, bool overwrite);
109
-
110
-typedef struct QDictRenames {
111
- const char *from;
112
- const char *to;
113
-} QDictRenames;
114
-bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
115
116
#endif /* QDICT_H */
43
diff --git a/block.c b/block.c
117
diff --git a/block.c b/block.c
44
index XXXXXXX..XXXXXXX 100644
118
index XXXXXXX..XXXXXXX 100644
45
--- a/block.c
119
--- a/block.c
46
+++ b/block.c
120
+++ b/block.c
47
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
121
@@ -XXX,XX +XXX,XX @@
48
assert(!drv->bdrv_needs_filename || filename != NULL);
122
#include "block/block_int.h"
49
ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
123
#include "block/blockjob.h"
50
} else {
124
#include "block/nbd.h"
51
- if (file == NULL) {
125
+#include "block/qdict.h"
52
- error_setg(errp, "Can't use '%s' as a block driver for the "
126
#include "qemu/error-report.h"
53
- "protocol level", drv->format_name);
127
#include "module_block.h"
54
- ret = -EINVAL;
128
#include "qemu/module.h"
55
- goto free_and_fail;
129
diff --git a/block/gluster.c b/block/gluster.c
56
- }
130
index XXXXXXX..XXXXXXX 100644
57
- bs->file = file;
131
--- a/block/gluster.c
58
ret = drv->bdrv_open(bs, options, open_flags, &local_err);
132
+++ b/block/gluster.c
59
}
133
@@ -XXX,XX +XXX,XX @@
60
134
#include "qemu/osdep.h"
61
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
135
#include <glusterfs/api/glfs.h>
62
return 0;
136
#include "block/block_int.h"
63
137
+#include "block/qdict.h"
64
free_and_fail:
138
#include "qapi/error.h"
65
- bs->file = NULL;
139
#include "qapi/qmp/qdict.h"
66
g_free(bs->opaque);
140
#include "qapi/qmp/qerror.h"
67
bs->opaque = NULL;
141
diff --git a/block/iscsi.c b/block/iscsi.c
68
bs->drv = NULL;
142
index XXXXXXX..XXXXXXX 100644
69
@@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
143
--- a/block/iscsi.c
70
}
144
+++ b/block/iscsi.c
71
145
@@ -XXX,XX +XXX,XX @@
72
if (child->bs->inherits_from == parent) {
146
#include "qemu/bitops.h"
73
- child->bs->inherits_from = NULL;
147
#include "qemu/bitmap.h"
74
+ BdrvChild *c;
148
#include "block/block_int.h"
75
+
149
+#include "block/qdict.h"
76
+ /* Remove inherits_from only when the last reference between parent and
150
#include "scsi/constants.h"
77
+ * child->bs goes away. */
151
#include "qemu/iov.h"
78
+ QLIST_FOREACH(c, &parent->children, next) {
152
#include "qemu/option.h"
79
+ if (c != child && c->bs == child->bs) {
153
diff --git a/block/nbd.c b/block/nbd.c
80
+ break;
154
index XXXXXXX..XXXXXXX 100644
81
+ }
155
--- a/block/nbd.c
82
+ }
156
+++ b/block/nbd.c
83
+ if (c == NULL) {
157
@@ -XXX,XX +XXX,XX @@
84
+ child->bs->inherits_from = NULL;
158
85
+ }
159
#include "qemu/osdep.h"
86
}
160
#include "nbd-client.h"
87
161
+#include "block/qdict.h"
88
bdrv_root_unref_child(child);
162
#include "qapi/error.h"
89
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
163
#include "qemu/uri.h"
90
qdict_del(options, "backing");
164
#include "block/block_int.h"
91
}
165
diff --git a/block/nfs.c b/block/nfs.c
92
166
index XXXXXXX..XXXXXXX 100644
93
- /* Open image file without format layer */
167
--- a/block/nfs.c
94
+ /* Open image file without format layer. This BdrvChild is only used for
168
+++ b/block/nfs.c
95
+ * probing, the block drivers will do their own bdrv_open_child() for the
169
@@ -XXX,XX +XXX,XX @@
96
+ * same BDS, which is why we put the node name back into options. */
170
#include "qemu/error-report.h"
97
if ((flags & BDRV_O_PROTOCOL) == 0) {
171
#include "qapi/error.h"
98
+ /* FIXME Shouldn't attach a child to a node that isn't opened yet. */
172
#include "block/block_int.h"
99
file = bdrv_open_child(filename, options, "file", bs,
173
+#include "block/qdict.h"
100
&child_file, true, &local_err);
174
#include "trace.h"
101
if (local_err) {
175
#include "qemu/iov.h"
102
goto fail;
176
#include "qemu/option.h"
103
}
104
+ if (file != NULL) {
105
+ qdict_put(options, "file",
106
+ qstring_from_str(bdrv_get_node_name(file->bs)));
107
+ }
108
}
109
110
/* Image format probing */
111
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
112
goto fail;
113
}
114
115
- if (file && (bs->file != file)) {
116
+ if (file) {
117
bdrv_unref_child(bs, file);
118
file = NULL;
119
}
120
@@ -XXX,XX +XXX,XX @@ fail:
121
if (file != NULL) {
122
bdrv_unref_child(bs, file);
123
}
124
+ if (bs->file != NULL) {
125
+ bdrv_unref_child(bs, bs->file);
126
+ }
127
QDECREF(snapshot_options);
128
QDECREF(bs->explicit_options);
129
QDECREF(bs->options);
130
diff --git a/block/bochs.c b/block/bochs.c
131
index XXXXXXX..XXXXXXX 100644
132
--- a/block/bochs.c
133
+++ b/block/bochs.c
134
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
135
struct bochs_header bochs;
136
int ret;
137
138
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
139
+ false, errp);
140
+ if (!bs->file) {
141
+ return -EINVAL;
142
+ }
143
+
144
bs->read_only = true; /* no write support yet */
145
146
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
147
diff --git a/block/cloop.c b/block/cloop.c
148
index XXXXXXX..XXXXXXX 100644
149
--- a/block/cloop.c
150
+++ b/block/cloop.c
151
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
152
uint32_t offsets_size, max_compressed_block_size = 1, i;
153
int ret;
154
155
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
156
+ false, errp);
157
+ if (!bs->file) {
158
+ return -EINVAL;
159
+ }
160
+
161
bs->read_only = true;
162
163
/* read header */
164
diff --git a/block/crypto.c b/block/crypto.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/block/crypto.c
167
+++ b/block/crypto.c
168
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
169
QCryptoBlockOpenOptions *open_opts = NULL;
170
unsigned int cflags = 0;
171
172
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
173
+ false, errp);
174
+ if (!bs->file) {
175
+ return -EINVAL;
176
+ }
177
+
178
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
179
qemu_opts_absorb_qdict(opts, options, &local_err);
180
if (local_err) {
181
diff --git a/block/dmg.c b/block/dmg.c
182
index XXXXXXX..XXXXXXX 100644
183
--- a/block/dmg.c
184
+++ b/block/dmg.c
185
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
186
int64_t offset;
187
int ret;
188
189
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
190
+ false, errp);
191
+ if (!bs->file) {
192
+ return -EINVAL;
193
+ }
194
+
195
block_module_load_one("dmg-bz2");
196
bs->read_only = true;
197
198
diff --git a/block/parallels.c b/block/parallels.c
177
diff --git a/block/parallels.c b/block/parallels.c
199
index XXXXXXX..XXXXXXX 100644
178
index XXXXXXX..XXXXXXX 100644
200
--- a/block/parallels.c
179
--- a/block/parallels.c
201
+++ b/block/parallels.c
180
+++ b/block/parallels.c
202
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
181
@@ -XXX,XX +XXX,XX @@
203
Error *local_err = NULL;
182
#include "qemu/osdep.h"
204
char *buf;
183
#include "qapi/error.h"
205
184
#include "block/block_int.h"
206
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
185
+#include "block/qdict.h"
207
+ false, errp);
186
#include "sysemu/block-backend.h"
208
+ if (!bs->file) {
187
#include "qemu/module.h"
209
+ return -EINVAL;
188
#include "qemu/option.h"
210
+ }
211
+
212
ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
213
if (ret < 0) {
214
goto fail;
215
diff --git a/block/qcow.c b/block/qcow.c
189
diff --git a/block/qcow.c b/block/qcow.c
216
index XXXXXXX..XXXXXXX 100644
190
index XXXXXXX..XXXXXXX 100644
217
--- a/block/qcow.c
191
--- a/block/qcow.c
218
+++ b/block/qcow.c
192
+++ b/block/qcow.c
219
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
193
@@ -XXX,XX +XXX,XX @@
220
QCowHeader header;
194
#include "qapi/error.h"
221
Error *local_err = NULL;
195
#include "qemu/error-report.h"
222
196
#include "block/block_int.h"
223
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
197
+#include "block/qdict.h"
224
+ false, errp);
198
#include "sysemu/block-backend.h"
225
+ if (!bs->file) {
199
#include "qemu/module.h"
226
+ return -EINVAL;
200
#include "qemu/option.h"
227
+ }
228
+
229
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
230
if (ret < 0) {
231
goto fail;
232
diff --git a/block/qcow2.c b/block/qcow2.c
201
diff --git a/block/qcow2.c b/block/qcow2.c
233
index XXXXXXX..XXXXXXX 100644
202
index XXXXXXX..XXXXXXX 100644
234
--- a/block/qcow2.c
203
--- a/block/qcow2.c
235
+++ b/block/qcow2.c
204
+++ b/block/qcow2.c
236
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
205
@@ -XXX,XX +XXX,XX @@
237
return ret;
206
238
}
207
#include "qemu/osdep.h"
239
208
#include "block/block_int.h"
240
-static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
209
+#include "block/qdict.h"
241
- Error **errp)
210
#include "sysemu/block-backend.h"
242
+static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
211
#include "qemu/module.h"
243
+ Error **errp)
212
#include <zlib.h>
244
{
245
BDRVQcow2State *s = bs->opaque;
246
unsigned int len, i;
247
@@ -XXX,XX +XXX,XX @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
248
return ret;
249
}
250
251
+static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
252
+ Error **errp)
253
+{
254
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
255
+ false, errp);
256
+ if (!bs->file) {
257
+ return -EINVAL;
258
+ }
259
+
260
+ return qcow2_do_open(bs, options, flags, errp);
261
+}
262
+
263
static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
264
{
265
BDRVQcow2State *s = bs->opaque;
266
@@ -XXX,XX +XXX,XX @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
267
options = qdict_clone_shallow(bs->options);
268
269
flags &= ~BDRV_O_INACTIVE;
270
- ret = qcow2_open(bs, options, flags, &local_err);
271
+ ret = qcow2_do_open(bs, options, flags, &local_err);
272
QDECREF(options);
273
if (local_err) {
274
error_propagate(errp, local_err);
275
diff --git a/block/qed.c b/block/qed.c
213
diff --git a/block/qed.c b/block/qed.c
276
index XXXXXXX..XXXXXXX 100644
214
index XXXXXXX..XXXXXXX 100644
277
--- a/block/qed.c
215
--- a/block/qed.c
278
+++ b/block/qed.c
216
+++ b/block/qed.c
279
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_drain(BlockDriverState *bs)
217
@@ -XXX,XX +XXX,XX @@
280
}
218
*/
281
}
219
282
220
#include "qemu/osdep.h"
283
-static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
221
+#include "block/qdict.h"
284
- Error **errp)
222
#include "qapi/error.h"
285
+static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
223
#include "qemu/timer.h"
286
+ Error **errp)
224
#include "qemu/bswap.h"
287
{
225
diff --git a/block/quorum.c b/block/quorum.c
288
BDRVQEDState *s = bs->opaque;
226
index XXXXXXX..XXXXXXX 100644
289
QEDHeader le_header;
227
--- a/block/quorum.c
290
@@ -XXX,XX +XXX,XX @@ out:
228
+++ b/block/quorum.c
291
return ret;
229
@@ -XXX,XX +XXX,XX @@
292
}
230
#include "qemu/cutils.h"
293
231
#include "qemu/option.h"
294
+static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
232
#include "block/block_int.h"
295
+ Error **errp)
233
+#include "block/qdict.h"
296
+{
234
#include "qapi/error.h"
297
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
235
#include "qapi/qapi-events-block.h"
298
+ false, errp);
236
#include "qapi/qmp/qdict.h"
299
+ if (!bs->file) {
237
diff --git a/block/rbd.c b/block/rbd.c
300
+ return -EINVAL;
238
index XXXXXXX..XXXXXXX 100644
301
+ }
239
--- a/block/rbd.c
302
+
240
+++ b/block/rbd.c
303
+ return bdrv_qed_do_open(bs, options, flags, errp);
241
@@ -XXX,XX +XXX,XX @@
304
+}
242
#include "qemu/error-report.h"
305
+
243
#include "qemu/option.h"
306
static void bdrv_qed_refresh_limits(BlockDriverState *bs, Error **errp)
244
#include "block/block_int.h"
307
{
245
+#include "block/qdict.h"
308
BDRVQEDState *s = bs->opaque;
246
#include "crypto/secret.h"
309
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
247
#include "qemu/cutils.h"
310
bdrv_qed_close(bs);
248
#include "qapi/qmp/qstring.h"
311
249
diff --git a/block/sheepdog.c b/block/sheepdog.c
312
memset(s, 0, sizeof(BDRVQEDState));
250
index XXXXXXX..XXXXXXX 100644
313
- ret = bdrv_qed_open(bs, NULL, bs->open_flags, &local_err);
251
--- a/block/sheepdog.c
314
+ ret = bdrv_qed_do_open(bs, NULL, bs->open_flags, &local_err);
252
+++ b/block/sheepdog.c
315
if (local_err) {
253
@@ -XXX,XX +XXX,XX @@
316
error_propagate(errp, local_err);
254
#include "qemu/option.h"
317
error_prepend(errp, "Could not reopen qed layer: ");
255
#include "qemu/sockets.h"
318
diff --git a/block/raw-format.c b/block/raw-format.c
256
#include "block/block_int.h"
319
index XXXXXXX..XXXXXXX 100644
257
+#include "block/qdict.h"
320
--- a/block/raw-format.c
258
#include "sysemu/block-backend.h"
321
+++ b/block/raw-format.c
259
#include "qemu/bitops.h"
322
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
260
#include "qemu/cutils.h"
323
BDRVRawState *s = bs->opaque;
261
diff --git a/block/snapshot.c b/block/snapshot.c
324
int ret;
262
index XXXXXXX..XXXXXXX 100644
325
263
--- a/block/snapshot.c
326
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
264
+++ b/block/snapshot.c
327
+ false, errp);
265
@@ -XXX,XX +XXX,XX @@
328
+ if (!bs->file) {
266
#include "qemu/osdep.h"
329
+ return -EINVAL;
267
#include "block/snapshot.h"
330
+ }
268
#include "block/block_int.h"
331
+
269
+#include "block/qdict.h"
332
bs->sg = bs->file->bs->sg;
270
#include "qapi/error.h"
333
bs->supported_write_flags = BDRV_REQ_FUA &
271
#include "qapi/qmp/qdict.h"
334
bs->file->bs->supported_write_flags;
272
#include "qapi/qmp/qerror.h"
335
diff --git a/block/replication.c b/block/replication.c
273
diff --git a/block/ssh.c b/block/ssh.c
336
index XXXXXXX..XXXXXXX 100644
274
index XXXXXXX..XXXXXXX 100644
337
--- a/block/replication.c
275
--- a/block/ssh.c
338
+++ b/block/replication.c
276
+++ b/block/ssh.c
339
@@ -XXX,XX +XXX,XX @@ static int replication_open(BlockDriverState *bs, QDict *options,
277
@@ -XXX,XX +XXX,XX @@
340
const char *mode;
278
#include <libssh2_sftp.h>
341
const char *top_id;
279
342
280
#include "block/block_int.h"
343
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
281
+#include "block/qdict.h"
344
+ false, errp);
282
#include "qapi/error.h"
345
+ if (!bs->file) {
283
#include "qemu/error-report.h"
346
+ return -EINVAL;
284
#include "qemu/option.h"
347
+ }
348
+
349
ret = -EINVAL;
350
opts = qemu_opts_create(&replication_runtime_opts, NULL, 0, &error_abort);
351
qemu_opts_absorb_qdict(opts, options, &local_err);
352
diff --git a/block/vdi.c b/block/vdi.c
353
index XXXXXXX..XXXXXXX 100644
354
--- a/block/vdi.c
355
+++ b/block/vdi.c
356
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
357
int ret;
358
Error *local_err = NULL;
359
360
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
361
+ false, errp);
362
+ if (!bs->file) {
363
+ return -EINVAL;
364
+ }
365
+
366
logout("\n");
367
368
ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
369
diff --git a/block/vhdx.c b/block/vhdx.c
285
diff --git a/block/vhdx.c b/block/vhdx.c
370
index XXXXXXX..XXXXXXX 100644
286
index XXXXXXX..XXXXXXX 100644
371
--- a/block/vhdx.c
287
--- a/block/vhdx.c
372
+++ b/block/vhdx.c
288
+++ b/block/vhdx.c
373
@@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
289
@@ -XXX,XX +XXX,XX @@
374
uint64_t signature;
290
#include "qemu/osdep.h"
375
Error *local_err = NULL;
291
#include "qapi/error.h"
376
292
#include "block/block_int.h"
377
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
293
+#include "block/qdict.h"
378
+ false, errp);
294
#include "sysemu/block-backend.h"
379
+ if (!bs->file) {
295
#include "qemu/module.h"
380
+ return -EINVAL;
296
#include "qemu/option.h"
381
+ }
382
+
383
s->bat = NULL;
384
s->first_visible_write = true;
385
386
diff --git a/block/vmdk.c b/block/vmdk.c
387
index XXXXXXX..XXXXXXX 100644
388
--- a/block/vmdk.c
389
+++ b/block/vmdk.c
390
@@ -XXX,XX +XXX,XX @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
391
uint32_t magic;
392
Error *local_err = NULL;
393
394
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
395
+ false, errp);
396
+ if (!bs->file) {
397
+ return -EINVAL;
398
+ }
399
+
400
buf = vmdk_read_desc(bs->file, 0, errp);
401
if (!buf) {
402
return -EINVAL;
403
diff --git a/block/vpc.c b/block/vpc.c
297
diff --git a/block/vpc.c b/block/vpc.c
404
index XXXXXXX..XXXXXXX 100644
298
index XXXXXXX..XXXXXXX 100644
405
--- a/block/vpc.c
299
--- a/block/vpc.c
406
+++ b/block/vpc.c
300
+++ b/block/vpc.c
407
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
301
@@ -XXX,XX +XXX,XX @@
408
int disk_type = VHD_DYNAMIC;
302
#include "qemu/osdep.h"
409
int ret;
303
#include "qapi/error.h"
410
304
#include "block/block_int.h"
411
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
305
+#include "block/qdict.h"
412
+ false, errp);
306
#include "sysemu/block-backend.h"
413
+ if (!bs->file) {
307
#include "qemu/module.h"
414
+ return -EINVAL;
308
#include "qemu/option.h"
415
+ }
309
diff --git a/block/vvfat.c b/block/vvfat.c
416
+
310
index XXXXXXX..XXXXXXX 100644
417
opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
311
--- a/block/vvfat.c
418
qemu_opts_absorb_qdict(opts, options, &local_err);
312
+++ b/block/vvfat.c
419
if (local_err) {
313
@@ -XXX,XX +XXX,XX @@
420
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
314
#include <dirent.h>
421
index XXXXXXX..XXXXXXX 100644
315
#include "qapi/error.h"
422
--- a/tests/qemu-iotests/051.out
316
#include "block/block_int.h"
423
+++ b/tests/qemu-iotests/051.out
317
+#include "block/qdict.h"
424
@@ -XXX,XX +XXX,XX @@ Testing: -drive driver=nbd
318
#include "qemu/module.h"
425
QEMU_PROG: -drive driver=nbd: NBD server address missing
319
#include "qemu/option.h"
426
320
#include "qemu/bswap.h"
427
Testing: -drive driver=raw
321
diff --git a/block/vxhs.c b/block/vxhs.c
428
-QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level
322
index XXXXXXX..XXXXXXX 100644
429
+QEMU_PROG: -drive driver=raw: A block device must be specified for "file"
323
--- a/block/vxhs.c
430
324
+++ b/block/vxhs.c
431
Testing: -drive file.driver=file
325
@@ -XXX,XX +XXX,XX @@
432
QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name
326
#include <qnio/qnio_api.h>
433
@@ -XXX,XX +XXX,XX @@ Testing: -drive file.driver=nbd
327
#include <sys/param.h>
434
QEMU_PROG: -drive file.driver=nbd: NBD server address missing
328
#include "block/block_int.h"
435
329
+#include "block/qdict.h"
436
Testing: -drive file.driver=raw
330
#include "qapi/qmp/qerror.h"
437
-QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level
331
#include "qapi/qmp/qdict.h"
438
+QEMU_PROG: -drive file.driver=raw: A block device must be specified for "file"
332
#include "qapi/qmp/qstring.h"
439
333
diff --git a/blockdev.c b/blockdev.c
440
Testing: -drive foo=bar
334
index XXXXXXX..XXXXXXX 100644
441
QEMU_PROG: -drive foo=bar: Must specify either driver or file
335
--- a/blockdev.c
442
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
336
+++ b/blockdev.c
443
index XXXXXXX..XXXXXXX 100644
337
@@ -XXX,XX +XXX,XX @@
444
--- a/tests/qemu-iotests/051.pc.out
338
#include "sysemu/blockdev.h"
445
+++ b/tests/qemu-iotests/051.pc.out
339
#include "hw/block/block.h"
446
@@ -XXX,XX +XXX,XX @@ Testing: -drive driver=nbd
340
#include "block/blockjob.h"
447
QEMU_PROG: -drive driver=nbd: NBD server address missing
341
+#include "block/qdict.h"
448
342
#include "block/throttle-groups.h"
449
Testing: -drive driver=raw
343
#include "monitor/monitor.h"
450
-QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level
344
#include "qemu/error-report.h"
451
+QEMU_PROG: -drive driver=raw: A block device must be specified for "file"
345
diff --git a/qobject/qdict.c b/qobject/qdict.c
452
346
index XXXXXXX..XXXXXXX 100644
453
Testing: -drive file.driver=file
347
--- a/qobject/qdict.c
454
QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name
348
+++ b/qobject/qdict.c
455
@@ -XXX,XX +XXX,XX @@ Testing: -drive file.driver=nbd
349
@@ -XXX,XX +XXX,XX @@
456
QEMU_PROG: -drive file.driver=nbd: NBD server address missing
350
*/
457
351
458
Testing: -drive file.driver=raw
352
#include "qemu/osdep.h"
459
-QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level
353
+#include "block/qdict.h"
460
+QEMU_PROG: -drive file.driver=raw: A block device must be specified for "file"
354
#include "qapi/qmp/qnum.h"
461
355
#include "qapi/qmp/qdict.h"
462
Testing: -drive foo=bar
356
#include "qapi/qmp/qbool.h"
463
QEMU_PROG: -drive foo=bar: Must specify either driver or file
357
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
358
index XXXXXXX..XXXXXXX 100644
359
--- a/tests/check-qdict.c
360
+++ b/tests/check-qdict.c
361
@@ -XXX,XX +XXX,XX @@
362
*/
363
364
#include "qemu/osdep.h"
365
+#include "block/qdict.h"
366
#include "qapi/qmp/qdict.h"
367
#include "qapi/qmp/qlist.h"
368
#include "qapi/qmp/qnum.h"
369
diff --git a/tests/check-qobject.c b/tests/check-qobject.c
370
index XXXXXXX..XXXXXXX 100644
371
--- a/tests/check-qobject.c
372
+++ b/tests/check-qobject.c
373
@@ -XXX,XX +XXX,XX @@
374
*/
375
376
#include "qemu/osdep.h"
377
+#include "block/qdict.h"
378
#include "qapi/qmp/qbool.h"
379
#include "qapi/qmp/qdict.h"
380
#include "qapi/qmp/qlist.h"
381
diff --git a/tests/test-replication.c b/tests/test-replication.c
382
index XXXXXXX..XXXXXXX 100644
383
--- a/tests/test-replication.c
384
+++ b/tests/test-replication.c
385
@@ -XXX,XX +XXX,XX @@
386
#include "qemu/option.h"
387
#include "replication.h"
388
#include "block/block_int.h"
389
+#include "block/qdict.h"
390
#include "sysemu/block-backend.h"
391
392
#define IMG_SIZE (64 * 1024 * 1024)
393
diff --git a/util/qemu-config.c b/util/qemu-config.c
394
index XXXXXXX..XXXXXXX 100644
395
--- a/util/qemu-config.c
396
+++ b/util/qemu-config.c
397
@@ -XXX,XX +XXX,XX @@
398
#include "qemu/osdep.h"
399
+#include "block/qdict.h" /* for qdict_extract_subqdict() */
400
#include "qapi/error.h"
401
#include "qapi/qapi-commands-misc.h"
402
#include "qapi/qmp/qdict.h"
464
--
403
--
465
1.8.3.1
404
2.13.6
466
405
467
406
diff view generated by jsdifflib
1
This is more consistent with the commit block job, and it moves the code
1
From: Markus Armbruster <armbru@redhat.com>
2
to a place where we already have the necessary BlockBackends to resize
3
the base image when bdrv_truncate() is changed to require a BdrvChild.
4
2
3
Pure code motion, except for two brace placements and a comment
4
tweaked to appease checkpatch.
5
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
9
---
8
block/mirror.c | 50 ++++++++++++++++++++++----------------------------
10
qobject/block-qdict.c | 640 ++++++++++++++++++++++++++++++++++++++++++++
9
1 file changed, 22 insertions(+), 28 deletions(-)
11
qobject/qdict.c | 629 --------------------------------------------
12
tests/check-block-qdict.c | 655 ++++++++++++++++++++++++++++++++++++++++++++++
13
tests/check-qdict.c | 642 ---------------------------------------------
14
MAINTAINERS | 2 +
15
qobject/Makefile.objs | 1 +
16
tests/Makefile.include | 4 +
17
7 files changed, 1302 insertions(+), 1271 deletions(-)
18
create mode 100644 qobject/block-qdict.c
19
create mode 100644 tests/check-block-qdict.c
10
20
11
diff --git a/block/mirror.c b/block/mirror.c
21
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
12
index XXXXXXX..XXXXXXX 100644
22
new file mode 100644
13
--- a/block/mirror.c
23
index XXXXXXX..XXXXXXX
14
+++ b/block/mirror.c
24
--- /dev/null
15
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
25
+++ b/qobject/block-qdict.c
16
if (s->bdev_length < 0) {
26
@@ -XXX,XX +XXX,XX @@
17
ret = s->bdev_length;
27
+/*
18
goto immediate_exit;
28
+ * Special QDict functions used by the block layer
19
- } else if (s->bdev_length == 0) {
29
+ *
30
+ * Copyright (c) 2013-2018 Red Hat, Inc.
31
+ *
32
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
33
+ * See the COPYING.LIB file in the top-level directory.
34
+ */
35
+
36
+#include "qemu/osdep.h"
37
+#include "block/qdict.h"
38
+#include "qapi/qmp/qlist.h"
39
+#include "qemu/cutils.h"
40
+#include "qapi/error.h"
41
+
42
+/**
43
+ * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
44
+ * value of 'key' in 'src' is copied there (and the refcount increased
45
+ * accordingly).
46
+ */
47
+void qdict_copy_default(QDict *dst, QDict *src, const char *key)
48
+{
49
+ QObject *val;
50
+
51
+ if (qdict_haskey(dst, key)) {
52
+ return;
20
+ }
53
+ }
21
+
54
+
22
+ /* Active commit must resize the base image if its size differs from the
55
+ val = qdict_get(src, key);
23
+ * active layer. */
56
+ if (val) {
24
+ if (s->base == blk_bs(s->target)) {
57
+ qdict_put_obj(dst, key, qobject_ref(val));
25
+ int64_t base_length;
58
+ }
26
+
59
+}
27
+ base_length = blk_getlength(s->target);
60
+
28
+ if (base_length < 0) {
61
+/**
29
+ ret = base_length;
62
+ * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
30
+ goto immediate_exit;
63
+ * new QString initialised by 'val' is put there.
64
+ */
65
+void qdict_set_default_str(QDict *dst, const char *key, const char *val)
66
+{
67
+ if (qdict_haskey(dst, key)) {
68
+ return;
69
+ }
70
+
71
+ qdict_put_str(dst, key, val);
72
+}
73
+
74
+static void qdict_flatten_qdict(QDict *qdict, QDict *target,
75
+ const char *prefix);
76
+
77
+static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
78
+{
79
+ QObject *value;
80
+ const QListEntry *entry;
81
+ char *new_key;
82
+ int i;
83
+
84
+ /* This function is never called with prefix == NULL, i.e., it is always
85
+ * called from within qdict_flatten_q(list|dict)(). Therefore, it does not
86
+ * need to remove list entries during the iteration (the whole list will be
87
+ * deleted eventually anyway from qdict_flatten_qdict()). */
88
+ assert(prefix);
89
+
90
+ entry = qlist_first(qlist);
91
+
92
+ for (i = 0; entry; entry = qlist_next(entry), i++) {
93
+ value = qlist_entry_obj(entry);
94
+ new_key = g_strdup_printf("%s.%i", prefix, i);
95
+
96
+ if (qobject_type(value) == QTYPE_QDICT) {
97
+ qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
98
+ } else if (qobject_type(value) == QTYPE_QLIST) {
99
+ qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
100
+ } else {
101
+ /* All other types are moved to the target unchanged. */
102
+ qdict_put_obj(target, new_key, qobject_ref(value));
31
+ }
103
+ }
32
+
104
+
33
+ if (s->bdev_length > base_length) {
105
+ g_free(new_key);
34
+ ret = blk_truncate(s->target, s->bdev_length);
106
+ }
35
+ if (ret < 0) {
107
+}
36
+ goto immediate_exit;
108
+
109
+static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
110
+{
111
+ QObject *value;
112
+ const QDictEntry *entry, *next;
113
+ char *new_key;
114
+ bool delete;
115
+
116
+ entry = qdict_first(qdict);
117
+
118
+ while (entry != NULL) {
119
+
120
+ next = qdict_next(qdict, entry);
121
+ value = qdict_entry_value(entry);
122
+ new_key = NULL;
123
+ delete = false;
124
+
125
+ if (prefix) {
126
+ new_key = g_strdup_printf("%s.%s", prefix, entry->key);
127
+ }
128
+
129
+ if (qobject_type(value) == QTYPE_QDICT) {
130
+ /* Entries of QDicts are processed recursively, the QDict object
131
+ * itself disappears. */
132
+ qdict_flatten_qdict(qobject_to(QDict, value), target,
133
+ new_key ? new_key : entry->key);
134
+ delete = true;
135
+ } else if (qobject_type(value) == QTYPE_QLIST) {
136
+ qdict_flatten_qlist(qobject_to(QList, value), target,
137
+ new_key ? new_key : entry->key);
138
+ delete = true;
139
+ } else if (prefix) {
140
+ /* All other objects are moved to the target unchanged. */
141
+ qdict_put_obj(target, new_key, qobject_ref(value));
142
+ delete = true;
143
+ }
144
+
145
+ g_free(new_key);
146
+
147
+ if (delete) {
148
+ qdict_del(qdict, entry->key);
149
+
150
+ /* Restart loop after modifying the iterated QDict */
151
+ entry = qdict_first(qdict);
152
+ continue;
153
+ }
154
+
155
+ entry = next;
156
+ }
157
+}
158
+
159
+/**
160
+ * qdict_flatten(): For each nested QDict with key x, all fields with key y
161
+ * are moved to this QDict and their key is renamed to "x.y". For each nested
162
+ * QList with key x, the field at index y is moved to this QDict with the key
163
+ * "x.y" (i.e., the reverse of what qdict_array_split() does).
164
+ * This operation is applied recursively for nested QDicts and QLists.
165
+ */
166
+void qdict_flatten(QDict *qdict)
167
+{
168
+ qdict_flatten_qdict(qdict, qdict, NULL);
169
+}
170
+
171
+/* extract all the src QDict entries starting by start into dst */
172
+void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
173
+
174
+{
175
+ const QDictEntry *entry, *next;
176
+ const char *p;
177
+
178
+ *dst = qdict_new();
179
+ entry = qdict_first(src);
180
+
181
+ while (entry != NULL) {
182
+ next = qdict_next(src, entry);
183
+ if (strstart(entry->key, start, &p)) {
184
+ qdict_put_obj(*dst, p, qobject_ref(entry->value));
185
+ qdict_del(src, entry->key);
186
+ }
187
+ entry = next;
188
+ }
189
+}
190
+
191
+static int qdict_count_prefixed_entries(const QDict *src, const char *start)
192
+{
193
+ const QDictEntry *entry;
194
+ int count = 0;
195
+
196
+ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
197
+ if (strstart(entry->key, start, NULL)) {
198
+ if (count == INT_MAX) {
199
+ return -ERANGE;
200
+ }
201
+ count++;
202
+ }
203
+ }
204
+
205
+ return count;
206
+}
207
+
208
+/**
209
+ * qdict_array_split(): This function moves array-like elements of a QDict into
210
+ * a new QList. Every entry in the original QDict with a key "%u" or one
211
+ * prefixed "%u.", where %u designates an unsigned integer starting at 0 and
212
+ * incrementally counting up, will be moved to a new QDict at index %u in the
213
+ * output QList with the key prefix removed, if that prefix is "%u.". If the
214
+ * whole key is just "%u", the whole QObject will be moved unchanged without
215
+ * creating a new QDict. The function terminates when there is no entry in the
216
+ * QDict with a prefix directly (incrementally) following the last one; it also
217
+ * returns if there are both entries with "%u" and "%u." for the same index %u.
218
+ * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66}
219
+ * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66})
220
+ * => [{"a": 42, "b": 23}, {"x": 0}, 66]
221
+ * and {"4.y": 1, "o.o": 7} (remainder of the old QDict)
222
+ */
223
+void qdict_array_split(QDict *src, QList **dst)
224
+{
225
+ unsigned i;
226
+
227
+ *dst = qlist_new();
228
+
229
+ for (i = 0; i < UINT_MAX; i++) {
230
+ QObject *subqobj;
231
+ bool is_subqdict;
232
+ QDict *subqdict;
233
+ char indexstr[32], prefix[32];
234
+ size_t snprintf_ret;
235
+
236
+ snprintf_ret = snprintf(indexstr, 32, "%u", i);
237
+ assert(snprintf_ret < 32);
238
+
239
+ subqobj = qdict_get(src, indexstr);
240
+
241
+ snprintf_ret = snprintf(prefix, 32, "%u.", i);
242
+ assert(snprintf_ret < 32);
243
+
244
+ /* Overflow is the same as positive non-zero results */
245
+ is_subqdict = qdict_count_prefixed_entries(src, prefix);
246
+
247
+ /*
248
+ * There may be either a single subordinate object (named
249
+ * "%u") or multiple objects (each with a key prefixed "%u."),
250
+ * but not both.
251
+ */
252
+ if (!subqobj == !is_subqdict) {
253
+ break;
254
+ }
255
+
256
+ if (is_subqdict) {
257
+ qdict_extract_subqdict(src, &subqdict, prefix);
258
+ assert(qdict_size(subqdict) > 0);
259
+ } else {
260
+ qobject_ref(subqobj);
261
+ qdict_del(src, indexstr);
262
+ }
263
+
264
+ qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
265
+ }
266
+}
267
+
268
+/**
269
+ * qdict_split_flat_key:
270
+ * @key: the key string to split
271
+ * @prefix: non-NULL pointer to hold extracted prefix
272
+ * @suffix: non-NULL pointer to remaining suffix
273
+ *
274
+ * Given a flattened key such as 'foo.0.bar', split it into two parts
275
+ * at the first '.' separator. Allows double dot ('..') to escape the
276
+ * normal separator.
277
+ *
278
+ * e.g.
279
+ * 'foo.0.bar' -> prefix='foo' and suffix='0.bar'
280
+ * 'foo..0.bar' -> prefix='foo.0' and suffix='bar'
281
+ *
282
+ * The '..' sequence will be unescaped in the returned 'prefix'
283
+ * string. The 'suffix' string will be left in escaped format, so it
284
+ * can be fed back into the qdict_split_flat_key() key as the input
285
+ * later.
286
+ *
287
+ * The caller is responsible for freeing the string returned in @prefix
288
+ * using g_free().
289
+ */
290
+static void qdict_split_flat_key(const char *key, char **prefix,
291
+ const char **suffix)
292
+{
293
+ const char *separator;
294
+ size_t i, j;
295
+
296
+ /* Find first '.' separator, but if there is a pair '..'
297
+ * that acts as an escape, so skip over '..' */
298
+ separator = NULL;
299
+ do {
300
+ if (separator) {
301
+ separator += 2;
302
+ } else {
303
+ separator = key;
304
+ }
305
+ separator = strchr(separator, '.');
306
+ } while (separator && separator[1] == '.');
307
+
308
+ if (separator) {
309
+ *prefix = g_strndup(key, separator - key);
310
+ *suffix = separator + 1;
311
+ } else {
312
+ *prefix = g_strdup(key);
313
+ *suffix = NULL;
314
+ }
315
+
316
+ /* Unescape the '..' sequence into '.' */
317
+ for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) {
318
+ if ((*prefix)[i] == '.') {
319
+ assert((*prefix)[i + 1] == '.');
320
+ i++;
321
+ }
322
+ (*prefix)[j] = (*prefix)[i];
323
+ }
324
+ (*prefix)[j] = '\0';
325
+}
326
+
327
+/**
328
+ * qdict_is_list:
329
+ * @maybe_list: dict to check if keys represent list elements.
330
+ *
331
+ * Determine whether all keys in @maybe_list are valid list elements.
332
+ * If @maybe_list is non-zero in length and all the keys look like
333
+ * valid list indexes, this will return 1. If @maybe_list is zero
334
+ * length or all keys are non-numeric then it will return 0 to indicate
335
+ * it is a normal qdict. If there is a mix of numeric and non-numeric
336
+ * keys, or the list indexes are non-contiguous, an error is reported.
337
+ *
338
+ * Returns: 1 if a valid list, 0 if a dict, -1 on error
339
+ */
340
+static int qdict_is_list(QDict *maybe_list, Error **errp)
341
+{
342
+ const QDictEntry *ent;
343
+ ssize_t len = 0;
344
+ ssize_t max = -1;
345
+ int is_list = -1;
346
+ int64_t val;
347
+
348
+ for (ent = qdict_first(maybe_list); ent != NULL;
349
+ ent = qdict_next(maybe_list, ent)) {
350
+
351
+ if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
352
+ if (is_list == -1) {
353
+ is_list = 1;
354
+ } else if (!is_list) {
355
+ error_setg(errp,
356
+ "Cannot mix list and non-list keys");
357
+ return -1;
358
+ }
359
+ len++;
360
+ if (val > max) {
361
+ max = val;
362
+ }
363
+ } else {
364
+ if (is_list == -1) {
365
+ is_list = 0;
366
+ } else if (is_list) {
367
+ error_setg(errp,
368
+ "Cannot mix list and non-list keys");
369
+ return -1;
37
+ }
370
+ }
38
+ }
371
+ }
39
+ }
372
+ }
40
+
373
+
41
+ if (s->bdev_length == 0) {
374
+ if (is_list == -1) {
42
/* Report BLOCK_JOB_READY and wait for complete. */
375
+ assert(!qdict_size(maybe_list));
43
block_job_event_ready(&s->common);
376
+ is_list = 0;
44
s->synced = true;
377
+ }
45
@@ -XXX,XX +XXX,XX @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
378
+
46
BlockCompletionFunc *cb, void *opaque, Error **errp,
379
+ /* NB this isn't a perfect check - e.g. it won't catch
47
bool auto_complete)
380
+ * a list containing '1', '+1', '01', '3', but that
48
{
381
+ * does not matter - we've still proved that the
49
- int64_t length, base_length;
382
+ * input is a list. It is up the caller to do a
50
int orig_base_flags;
383
+ * stricter check if desired */
51
- int ret;
384
+ if (len != (max + 1)) {
52
Error *local_err = NULL;
385
+ error_setg(errp, "List indices are not contiguous, "
53
386
+ "saw %zd elements but %zd largest index",
54
orig_base_flags = bdrv_get_flags(base);
387
+ len, max);
55
@@ -XXX,XX +XXX,XX @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
388
+ return -1;
56
return;
389
+ }
57
}
390
+
58
391
+ return is_list;
59
- length = bdrv_getlength(bs);
392
+}
60
- if (length < 0) {
393
+
61
- error_setg_errno(errp, -length,
394
+/**
62
- "Unable to determine length of %s", bs->filename);
395
+ * qdict_crumple:
63
- goto error_restore_flags;
396
+ * @src: the original flat dictionary (only scalar values) to crumple
397
+ *
398
+ * Takes a flat dictionary whose keys use '.' separator to indicate
399
+ * nesting, and values are scalars, and crumples it into a nested
400
+ * structure.
401
+ *
402
+ * To include a literal '.' in a key name, it must be escaped as '..'
403
+ *
404
+ * For example, an input of:
405
+ *
406
+ * { 'foo.0.bar': 'one', 'foo.0.wizz': '1',
407
+ * 'foo.1.bar': 'two', 'foo.1.wizz': '2' }
408
+ *
409
+ * will result in an output of:
410
+ *
411
+ * {
412
+ * 'foo': [
413
+ * { 'bar': 'one', 'wizz': '1' },
414
+ * { 'bar': 'two', 'wizz': '2' }
415
+ * ],
416
+ * }
417
+ *
418
+ * The following scenarios in the input dict will result in an
419
+ * error being returned:
420
+ *
421
+ * - Any values in @src are non-scalar types
422
+ * - If keys in @src imply that a particular level is both a
423
+ * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar".
424
+ * - If keys in @src imply that a particular level is a list,
425
+ * but the indices are non-contiguous. e.g. "foo.0.bar" and
426
+ * "foo.2.bar" without any "foo.1.bar" present.
427
+ * - If keys in @src represent list indexes, but are not in
428
+ * the "%zu" format. e.g. "foo.+0.bar"
429
+ *
430
+ * Returns: either a QDict or QList for the nested data structure, or NULL
431
+ * on error
432
+ */
433
+QObject *qdict_crumple(const QDict *src, Error **errp)
434
+{
435
+ const QDictEntry *ent;
436
+ QDict *two_level, *multi_level = NULL;
437
+ QObject *dst = NULL, *child;
438
+ size_t i;
439
+ char *prefix = NULL;
440
+ const char *suffix = NULL;
441
+ int is_list;
442
+
443
+ two_level = qdict_new();
444
+
445
+ /* Step 1: split our totally flat dict into a two level dict */
446
+ for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) {
447
+ if (qobject_type(ent->value) == QTYPE_QDICT ||
448
+ qobject_type(ent->value) == QTYPE_QLIST) {
449
+ error_setg(errp, "Value %s is not a scalar",
450
+ ent->key);
451
+ goto error;
452
+ }
453
+
454
+ qdict_split_flat_key(ent->key, &prefix, &suffix);
455
+
456
+ child = qdict_get(two_level, prefix);
457
+ if (suffix) {
458
+ QDict *child_dict = qobject_to(QDict, child);
459
+ if (!child_dict) {
460
+ if (child) {
461
+ error_setg(errp, "Key %s prefix is already set as a scalar",
462
+ prefix);
463
+ goto error;
464
+ }
465
+
466
+ child_dict = qdict_new();
467
+ qdict_put_obj(two_level, prefix, QOBJECT(child_dict));
468
+ }
469
+
470
+ qdict_put_obj(child_dict, suffix, qobject_ref(ent->value));
471
+ } else {
472
+ if (child) {
473
+ error_setg(errp, "Key %s prefix is already set as a dict",
474
+ prefix);
475
+ goto error;
476
+ }
477
+ qdict_put_obj(two_level, prefix, qobject_ref(ent->value));
478
+ }
479
+
480
+ g_free(prefix);
481
+ prefix = NULL;
482
+ }
483
+
484
+ /* Step 2: optionally process the two level dict recursively
485
+ * into a multi-level dict */
486
+ multi_level = qdict_new();
487
+ for (ent = qdict_first(two_level); ent != NULL;
488
+ ent = qdict_next(two_level, ent)) {
489
+ QDict *dict = qobject_to(QDict, ent->value);
490
+ if (dict) {
491
+ child = qdict_crumple(dict, errp);
492
+ if (!child) {
493
+ goto error;
494
+ }
495
+
496
+ qdict_put_obj(multi_level, ent->key, child);
497
+ } else {
498
+ qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value));
499
+ }
500
+ }
501
+ qobject_unref(two_level);
502
+ two_level = NULL;
503
+
504
+ /* Step 3: detect if we need to turn our dict into list */
505
+ is_list = qdict_is_list(multi_level, errp);
506
+ if (is_list < 0) {
507
+ goto error;
508
+ }
509
+
510
+ if (is_list) {
511
+ dst = QOBJECT(qlist_new());
512
+
513
+ for (i = 0; i < qdict_size(multi_level); i++) {
514
+ char *key = g_strdup_printf("%zu", i);
515
+
516
+ child = qdict_get(multi_level, key);
517
+ g_free(key);
518
+
519
+ if (!child) {
520
+ error_setg(errp, "Missing list index %zu", i);
521
+ goto error;
522
+ }
523
+
524
+ qlist_append_obj(qobject_to(QList, dst), qobject_ref(child));
525
+ }
526
+ qobject_unref(multi_level);
527
+ multi_level = NULL;
528
+ } else {
529
+ dst = QOBJECT(multi_level);
530
+ }
531
+
532
+ return dst;
533
+
534
+ error:
535
+ g_free(prefix);
536
+ qobject_unref(multi_level);
537
+ qobject_unref(two_level);
538
+ qobject_unref(dst);
539
+ return NULL;
540
+}
541
+
542
+/**
543
+ * qdict_array_entries(): Returns the number of direct array entries if the
544
+ * sub-QDict of src specified by the prefix in subqdict (or src itself for
545
+ * prefix == "") is valid as an array, i.e. the length of the created list if
546
+ * the sub-QDict would become empty after calling qdict_array_split() on it. If
547
+ * the array is not valid, -EINVAL is returned.
548
+ */
549
+int qdict_array_entries(QDict *src, const char *subqdict)
550
+{
551
+ const QDictEntry *entry;
552
+ unsigned i;
553
+ unsigned entries = 0;
554
+ size_t subqdict_len = strlen(subqdict);
555
+
556
+ assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
557
+
558
+ /* qdict_array_split() loops until UINT_MAX, but as we want to return
559
+ * negative errors, we only have a signed return value here. Any additional
560
+ * entries will lead to -EINVAL. */
561
+ for (i = 0; i < INT_MAX; i++) {
562
+ QObject *subqobj;
563
+ int subqdict_entries;
564
+ char *prefix = g_strdup_printf("%s%u.", subqdict, i);
565
+
566
+ subqdict_entries = qdict_count_prefixed_entries(src, prefix);
567
+
568
+ /* Remove ending "." */
569
+ prefix[strlen(prefix) - 1] = 0;
570
+ subqobj = qdict_get(src, prefix);
571
+
572
+ g_free(prefix);
573
+
574
+ if (subqdict_entries < 0) {
575
+ return subqdict_entries;
576
+ }
577
+
578
+ /* There may be either a single subordinate object (named "%u") or
579
+ * multiple objects (each with a key prefixed "%u."), but not both. */
580
+ if (subqobj && subqdict_entries) {
581
+ return -EINVAL;
582
+ } else if (!subqobj && !subqdict_entries) {
583
+ break;
584
+ }
585
+
586
+ entries += subqdict_entries ? subqdict_entries : 1;
587
+ }
588
+
589
+ /* Consider everything handled that isn't part of the given sub-QDict */
590
+ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
591
+ if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
592
+ entries++;
593
+ }
594
+ }
595
+
596
+ /* Anything left in the sub-QDict that wasn't handled? */
597
+ if (qdict_size(src) != entries) {
598
+ return -EINVAL;
599
+ }
600
+
601
+ return i;
602
+}
603
+
604
+/**
605
+ * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
606
+ * elements from src to dest.
607
+ *
608
+ * If an element from src has a key already present in dest, it will not be
609
+ * moved unless overwrite is true.
610
+ *
611
+ * If overwrite is true, the conflicting values in dest will be discarded and
612
+ * replaced by the corresponding values from src.
613
+ *
614
+ * Therefore, with overwrite being true, the src QDict will always be empty when
615
+ * this function returns. If overwrite is false, the src QDict will be empty
616
+ * iff there were no conflicts.
617
+ */
618
+void qdict_join(QDict *dest, QDict *src, bool overwrite)
619
+{
620
+ const QDictEntry *entry, *next;
621
+
622
+ entry = qdict_first(src);
623
+ while (entry) {
624
+ next = qdict_next(src, entry);
625
+
626
+ if (overwrite || !qdict_haskey(dest, entry->key)) {
627
+ qdict_put_obj(dest, entry->key, qobject_ref(entry->value));
628
+ qdict_del(src, entry->key);
629
+ }
630
+
631
+ entry = next;
632
+ }
633
+}
634
+
635
+/**
636
+ * qdict_rename_keys(): Rename keys in qdict according to the replacements
637
+ * specified in the array renames. The array must be terminated by an entry
638
+ * with from = NULL.
639
+ *
640
+ * The renames are performed individually in the order of the array, so entries
641
+ * may be renamed multiple times and may or may not conflict depending on the
642
+ * order of the renames array.
643
+ *
644
+ * Returns true for success, false in error cases.
645
+ */
646
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
647
+{
648
+ QObject *qobj;
649
+
650
+ while (renames->from) {
651
+ if (qdict_haskey(qdict, renames->from)) {
652
+ if (qdict_haskey(qdict, renames->to)) {
653
+ error_setg(errp, "'%s' and its alias '%s' can't be used at the "
654
+ "same time", renames->to, renames->from);
655
+ return false;
656
+ }
657
+
658
+ qobj = qdict_get(qdict, renames->from);
659
+ qdict_put_obj(qdict, renames->to, qobject_ref(qobj));
660
+ qdict_del(qdict, renames->from);
661
+ }
662
+
663
+ renames++;
664
+ }
665
+ return true;
666
+}
667
diff --git a/qobject/qdict.c b/qobject/qdict.c
668
index XXXXXXX..XXXXXXX 100644
669
--- a/qobject/qdict.c
670
+++ b/qobject/qdict.c
671
@@ -XXX,XX +XXX,XX @@
672
*/
673
674
#include "qemu/osdep.h"
675
-#include "block/qdict.h"
676
#include "qapi/qmp/qnum.h"
677
#include "qapi/qmp/qdict.h"
678
#include "qapi/qmp/qbool.h"
679
-#include "qapi/qmp/qlist.h"
680
#include "qapi/qmp/qnull.h"
681
#include "qapi/qmp/qstring.h"
682
-#include "qapi/error.h"
683
-#include "qemu/queue.h"
684
-#include "qemu-common.h"
685
-#include "qemu/cutils.h"
686
687
/**
688
* qdict_new(): Create a new QDict
689
@@ -XXX,XX +XXX,XX @@ void qdict_destroy_obj(QObject *obj)
690
691
g_free(qdict);
692
}
693
-
694
-/**
695
- * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
696
- * value of 'key' in 'src' is copied there (and the refcount increased
697
- * accordingly).
698
- */
699
-void qdict_copy_default(QDict *dst, QDict *src, const char *key)
700
-{
701
- QObject *val;
702
-
703
- if (qdict_haskey(dst, key)) {
704
- return;
64
- }
705
- }
65
-
706
-
66
- base_length = bdrv_getlength(base);
707
- val = qdict_get(src, key);
67
- if (base_length < 0) {
708
- if (val) {
68
- error_setg_errno(errp, -base_length,
709
- qdict_put_obj(dst, key, qobject_ref(val));
69
- "Unable to determine length of %s", base->filename);
70
- goto error_restore_flags;
71
- }
710
- }
72
-
711
-}
73
- if (length > base_length) {
712
-
74
- ret = bdrv_truncate(base, length);
713
-/**
75
- if (ret < 0) {
714
- * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
76
- error_setg_errno(errp, -ret,
715
- * new QString initialised by 'val' is put there.
77
- "Top image %s is larger than base image %s, and "
716
- */
78
- "resize of base image failed",
717
-void qdict_set_default_str(QDict *dst, const char *key, const char *val)
79
- bs->filename, base->filename);
718
-{
80
- goto error_restore_flags;
719
- if (qdict_haskey(dst, key)) {
720
- return;
721
- }
722
-
723
- qdict_put_str(dst, key, val);
724
-}
725
-
726
-static void qdict_flatten_qdict(QDict *qdict, QDict *target,
727
- const char *prefix);
728
-
729
-static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
730
-{
731
- QObject *value;
732
- const QListEntry *entry;
733
- char *new_key;
734
- int i;
735
-
736
- /* This function is never called with prefix == NULL, i.e., it is always
737
- * called from within qdict_flatten_q(list|dict)(). Therefore, it does not
738
- * need to remove list entries during the iteration (the whole list will be
739
- * deleted eventually anyway from qdict_flatten_qdict()). */
740
- assert(prefix);
741
-
742
- entry = qlist_first(qlist);
743
-
744
- for (i = 0; entry; entry = qlist_next(entry), i++) {
745
- value = qlist_entry_obj(entry);
746
- new_key = g_strdup_printf("%s.%i", prefix, i);
747
-
748
- if (qobject_type(value) == QTYPE_QDICT) {
749
- qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
750
- } else if (qobject_type(value) == QTYPE_QLIST) {
751
- qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
752
- } else {
753
- /* All other types are moved to the target unchanged. */
754
- qdict_put_obj(target, new_key, qobject_ref(value));
755
- }
756
-
757
- g_free(new_key);
758
- }
759
-}
760
-
761
-static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
762
-{
763
- QObject *value;
764
- const QDictEntry *entry, *next;
765
- char *new_key;
766
- bool delete;
767
-
768
- entry = qdict_first(qdict);
769
-
770
- while (entry != NULL) {
771
-
772
- next = qdict_next(qdict, entry);
773
- value = qdict_entry_value(entry);
774
- new_key = NULL;
775
- delete = false;
776
-
777
- if (prefix) {
778
- new_key = g_strdup_printf("%s.%s", prefix, entry->key);
779
- }
780
-
781
- if (qobject_type(value) == QTYPE_QDICT) {
782
- /* Entries of QDicts are processed recursively, the QDict object
783
- * itself disappears. */
784
- qdict_flatten_qdict(qobject_to(QDict, value), target,
785
- new_key ? new_key : entry->key);
786
- delete = true;
787
- } else if (qobject_type(value) == QTYPE_QLIST) {
788
- qdict_flatten_qlist(qobject_to(QList, value), target,
789
- new_key ? new_key : entry->key);
790
- delete = true;
791
- } else if (prefix) {
792
- /* All other objects are moved to the target unchanged. */
793
- qdict_put_obj(target, new_key, qobject_ref(value));
794
- delete = true;
795
- }
796
-
797
- g_free(new_key);
798
-
799
- if (delete) {
800
- qdict_del(qdict, entry->key);
801
-
802
- /* Restart loop after modifying the iterated QDict */
803
- entry = qdict_first(qdict);
804
- continue;
805
- }
806
-
807
- entry = next;
808
- }
809
-}
810
-
811
-/**
812
- * qdict_flatten(): For each nested QDict with key x, all fields with key y
813
- * are moved to this QDict and their key is renamed to "x.y". For each nested
814
- * QList with key x, the field at index y is moved to this QDict with the key
815
- * "x.y" (i.e., the reverse of what qdict_array_split() does).
816
- * This operation is applied recursively for nested QDicts and QLists.
817
- */
818
-void qdict_flatten(QDict *qdict)
819
-{
820
- qdict_flatten_qdict(qdict, qdict, NULL);
821
-}
822
-
823
-/* extract all the src QDict entries starting by start into dst */
824
-void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
825
-
826
-{
827
- const QDictEntry *entry, *next;
828
- const char *p;
829
-
830
- *dst = qdict_new();
831
- entry = qdict_first(src);
832
-
833
- while (entry != NULL) {
834
- next = qdict_next(src, entry);
835
- if (strstart(entry->key, start, &p)) {
836
- qdict_put_obj(*dst, p, qobject_ref(entry->value));
837
- qdict_del(src, entry->key);
838
- }
839
- entry = next;
840
- }
841
-}
842
-
843
-static int qdict_count_prefixed_entries(const QDict *src, const char *start)
844
-{
845
- const QDictEntry *entry;
846
- int count = 0;
847
-
848
- for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
849
- if (strstart(entry->key, start, NULL)) {
850
- if (count == INT_MAX) {
851
- return -ERANGE;
852
- }
853
- count++;
81
- }
854
- }
82
- }
855
- }
83
-
856
-
84
mirror_start_job(job_id, bs, creation_flags, base, NULL, speed, 0, 0,
857
- return count;
85
MIRROR_LEAVE_BACKING_CHAIN,
858
-}
86
on_error, on_error, true, cb, opaque, &local_err,
859
-
860
-/**
861
- * qdict_array_split(): This function moves array-like elements of a QDict into
862
- * a new QList. Every entry in the original QDict with a key "%u" or one
863
- * prefixed "%u.", where %u designates an unsigned integer starting at 0 and
864
- * incrementally counting up, will be moved to a new QDict at index %u in the
865
- * output QList with the key prefix removed, if that prefix is "%u.". If the
866
- * whole key is just "%u", the whole QObject will be moved unchanged without
867
- * creating a new QDict. The function terminates when there is no entry in the
868
- * QDict with a prefix directly (incrementally) following the last one; it also
869
- * returns if there are both entries with "%u" and "%u." for the same index %u.
870
- * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66}
871
- * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66})
872
- * => [{"a": 42, "b": 23}, {"x": 0}, 66]
873
- * and {"4.y": 1, "o.o": 7} (remainder of the old QDict)
874
- */
875
-void qdict_array_split(QDict *src, QList **dst)
876
-{
877
- unsigned i;
878
-
879
- *dst = qlist_new();
880
-
881
- for (i = 0; i < UINT_MAX; i++) {
882
- QObject *subqobj;
883
- bool is_subqdict;
884
- QDict *subqdict;
885
- char indexstr[32], prefix[32];
886
- size_t snprintf_ret;
887
-
888
- snprintf_ret = snprintf(indexstr, 32, "%u", i);
889
- assert(snprintf_ret < 32);
890
-
891
- subqobj = qdict_get(src, indexstr);
892
-
893
- snprintf_ret = snprintf(prefix, 32, "%u.", i);
894
- assert(snprintf_ret < 32);
895
-
896
- /* Overflow is the same as positive non-zero results */
897
- is_subqdict = qdict_count_prefixed_entries(src, prefix);
898
-
899
- // There may be either a single subordinate object (named "%u") or
900
- // multiple objects (each with a key prefixed "%u."), but not both.
901
- if (!subqobj == !is_subqdict) {
902
- break;
903
- }
904
-
905
- if (is_subqdict) {
906
- qdict_extract_subqdict(src, &subqdict, prefix);
907
- assert(qdict_size(subqdict) > 0);
908
- } else {
909
- qobject_ref(subqobj);
910
- qdict_del(src, indexstr);
911
- }
912
-
913
- qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
914
- }
915
-}
916
-
917
-/**
918
- * qdict_split_flat_key:
919
- * @key: the key string to split
920
- * @prefix: non-NULL pointer to hold extracted prefix
921
- * @suffix: non-NULL pointer to remaining suffix
922
- *
923
- * Given a flattened key such as 'foo.0.bar', split it into two parts
924
- * at the first '.' separator. Allows double dot ('..') to escape the
925
- * normal separator.
926
- *
927
- * e.g.
928
- * 'foo.0.bar' -> prefix='foo' and suffix='0.bar'
929
- * 'foo..0.bar' -> prefix='foo.0' and suffix='bar'
930
- *
931
- * The '..' sequence will be unescaped in the returned 'prefix'
932
- * string. The 'suffix' string will be left in escaped format, so it
933
- * can be fed back into the qdict_split_flat_key() key as the input
934
- * later.
935
- *
936
- * The caller is responsible for freeing the string returned in @prefix
937
- * using g_free().
938
- */
939
-static void qdict_split_flat_key(const char *key, char **prefix,
940
- const char **suffix)
941
-{
942
- const char *separator;
943
- size_t i, j;
944
-
945
- /* Find first '.' separator, but if there is a pair '..'
946
- * that acts as an escape, so skip over '..' */
947
- separator = NULL;
948
- do {
949
- if (separator) {
950
- separator += 2;
951
- } else {
952
- separator = key;
953
- }
954
- separator = strchr(separator, '.');
955
- } while (separator && separator[1] == '.');
956
-
957
- if (separator) {
958
- *prefix = g_strndup(key, separator - key);
959
- *suffix = separator + 1;
960
- } else {
961
- *prefix = g_strdup(key);
962
- *suffix = NULL;
963
- }
964
-
965
- /* Unescape the '..' sequence into '.' */
966
- for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) {
967
- if ((*prefix)[i] == '.') {
968
- assert((*prefix)[i + 1] == '.');
969
- i++;
970
- }
971
- (*prefix)[j] = (*prefix)[i];
972
- }
973
- (*prefix)[j] = '\0';
974
-}
975
-
976
-/**
977
- * qdict_is_list:
978
- * @maybe_list: dict to check if keys represent list elements.
979
- *
980
- * Determine whether all keys in @maybe_list are valid list elements.
981
- * If @maybe_list is non-zero in length and all the keys look like
982
- * valid list indexes, this will return 1. If @maybe_list is zero
983
- * length or all keys are non-numeric then it will return 0 to indicate
984
- * it is a normal qdict. If there is a mix of numeric and non-numeric
985
- * keys, or the list indexes are non-contiguous, an error is reported.
986
- *
987
- * Returns: 1 if a valid list, 0 if a dict, -1 on error
988
- */
989
-static int qdict_is_list(QDict *maybe_list, Error **errp)
990
-{
991
- const QDictEntry *ent;
992
- ssize_t len = 0;
993
- ssize_t max = -1;
994
- int is_list = -1;
995
- int64_t val;
996
-
997
- for (ent = qdict_first(maybe_list); ent != NULL;
998
- ent = qdict_next(maybe_list, ent)) {
999
-
1000
- if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
1001
- if (is_list == -1) {
1002
- is_list = 1;
1003
- } else if (!is_list) {
1004
- error_setg(errp,
1005
- "Cannot mix list and non-list keys");
1006
- return -1;
1007
- }
1008
- len++;
1009
- if (val > max) {
1010
- max = val;
1011
- }
1012
- } else {
1013
- if (is_list == -1) {
1014
- is_list = 0;
1015
- } else if (is_list) {
1016
- error_setg(errp,
1017
- "Cannot mix list and non-list keys");
1018
- return -1;
1019
- }
1020
- }
1021
- }
1022
-
1023
- if (is_list == -1) {
1024
- assert(!qdict_size(maybe_list));
1025
- is_list = 0;
1026
- }
1027
-
1028
- /* NB this isn't a perfect check - e.g. it won't catch
1029
- * a list containing '1', '+1', '01', '3', but that
1030
- * does not matter - we've still proved that the
1031
- * input is a list. It is up the caller to do a
1032
- * stricter check if desired */
1033
- if (len != (max + 1)) {
1034
- error_setg(errp, "List indices are not contiguous, "
1035
- "saw %zd elements but %zd largest index",
1036
- len, max);
1037
- return -1;
1038
- }
1039
-
1040
- return is_list;
1041
-}
1042
-
1043
-/**
1044
- * qdict_crumple:
1045
- * @src: the original flat dictionary (only scalar values) to crumple
1046
- *
1047
- * Takes a flat dictionary whose keys use '.' separator to indicate
1048
- * nesting, and values are scalars, and crumples it into a nested
1049
- * structure.
1050
- *
1051
- * To include a literal '.' in a key name, it must be escaped as '..'
1052
- *
1053
- * For example, an input of:
1054
- *
1055
- * { 'foo.0.bar': 'one', 'foo.0.wizz': '1',
1056
- * 'foo.1.bar': 'two', 'foo.1.wizz': '2' }
1057
- *
1058
- * will result in an output of:
1059
- *
1060
- * {
1061
- * 'foo': [
1062
- * { 'bar': 'one', 'wizz': '1' },
1063
- * { 'bar': 'two', 'wizz': '2' }
1064
- * ],
1065
- * }
1066
- *
1067
- * The following scenarios in the input dict will result in an
1068
- * error being returned:
1069
- *
1070
- * - Any values in @src are non-scalar types
1071
- * - If keys in @src imply that a particular level is both a
1072
- * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar".
1073
- * - If keys in @src imply that a particular level is a list,
1074
- * but the indices are non-contiguous. e.g. "foo.0.bar" and
1075
- * "foo.2.bar" without any "foo.1.bar" present.
1076
- * - If keys in @src represent list indexes, but are not in
1077
- * the "%zu" format. e.g. "foo.+0.bar"
1078
- *
1079
- * Returns: either a QDict or QList for the nested data structure, or NULL
1080
- * on error
1081
- */
1082
-QObject *qdict_crumple(const QDict *src, Error **errp)
1083
-{
1084
- const QDictEntry *ent;
1085
- QDict *two_level, *multi_level = NULL;
1086
- QObject *dst = NULL, *child;
1087
- size_t i;
1088
- char *prefix = NULL;
1089
- const char *suffix = NULL;
1090
- int is_list;
1091
-
1092
- two_level = qdict_new();
1093
-
1094
- /* Step 1: split our totally flat dict into a two level dict */
1095
- for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) {
1096
- if (qobject_type(ent->value) == QTYPE_QDICT ||
1097
- qobject_type(ent->value) == QTYPE_QLIST) {
1098
- error_setg(errp, "Value %s is not a scalar",
1099
- ent->key);
1100
- goto error;
1101
- }
1102
-
1103
- qdict_split_flat_key(ent->key, &prefix, &suffix);
1104
-
1105
- child = qdict_get(two_level, prefix);
1106
- if (suffix) {
1107
- QDict *child_dict = qobject_to(QDict, child);
1108
- if (!child_dict) {
1109
- if (child) {
1110
- error_setg(errp, "Key %s prefix is already set as a scalar",
1111
- prefix);
1112
- goto error;
1113
- }
1114
-
1115
- child_dict = qdict_new();
1116
- qdict_put_obj(two_level, prefix, QOBJECT(child_dict));
1117
- }
1118
-
1119
- qdict_put_obj(child_dict, suffix, qobject_ref(ent->value));
1120
- } else {
1121
- if (child) {
1122
- error_setg(errp, "Key %s prefix is already set as a dict",
1123
- prefix);
1124
- goto error;
1125
- }
1126
- qdict_put_obj(two_level, prefix, qobject_ref(ent->value));
1127
- }
1128
-
1129
- g_free(prefix);
1130
- prefix = NULL;
1131
- }
1132
-
1133
- /* Step 2: optionally process the two level dict recursively
1134
- * into a multi-level dict */
1135
- multi_level = qdict_new();
1136
- for (ent = qdict_first(two_level); ent != NULL;
1137
- ent = qdict_next(two_level, ent)) {
1138
- QDict *dict = qobject_to(QDict, ent->value);
1139
- if (dict) {
1140
- child = qdict_crumple(dict, errp);
1141
- if (!child) {
1142
- goto error;
1143
- }
1144
-
1145
- qdict_put_obj(multi_level, ent->key, child);
1146
- } else {
1147
- qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value));
1148
- }
1149
- }
1150
- qobject_unref(two_level);
1151
- two_level = NULL;
1152
-
1153
- /* Step 3: detect if we need to turn our dict into list */
1154
- is_list = qdict_is_list(multi_level, errp);
1155
- if (is_list < 0) {
1156
- goto error;
1157
- }
1158
-
1159
- if (is_list) {
1160
- dst = QOBJECT(qlist_new());
1161
-
1162
- for (i = 0; i < qdict_size(multi_level); i++) {
1163
- char *key = g_strdup_printf("%zu", i);
1164
-
1165
- child = qdict_get(multi_level, key);
1166
- g_free(key);
1167
-
1168
- if (!child) {
1169
- error_setg(errp, "Missing list index %zu", i);
1170
- goto error;
1171
- }
1172
-
1173
- qlist_append_obj(qobject_to(QList, dst), qobject_ref(child));
1174
- }
1175
- qobject_unref(multi_level);
1176
- multi_level = NULL;
1177
- } else {
1178
- dst = QOBJECT(multi_level);
1179
- }
1180
-
1181
- return dst;
1182
-
1183
- error:
1184
- g_free(prefix);
1185
- qobject_unref(multi_level);
1186
- qobject_unref(two_level);
1187
- qobject_unref(dst);
1188
- return NULL;
1189
-}
1190
-
1191
-/**
1192
- * qdict_array_entries(): Returns the number of direct array entries if the
1193
- * sub-QDict of src specified by the prefix in subqdict (or src itself for
1194
- * prefix == "") is valid as an array, i.e. the length of the created list if
1195
- * the sub-QDict would become empty after calling qdict_array_split() on it. If
1196
- * the array is not valid, -EINVAL is returned.
1197
- */
1198
-int qdict_array_entries(QDict *src, const char *subqdict)
1199
-{
1200
- const QDictEntry *entry;
1201
- unsigned i;
1202
- unsigned entries = 0;
1203
- size_t subqdict_len = strlen(subqdict);
1204
-
1205
- assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
1206
-
1207
- /* qdict_array_split() loops until UINT_MAX, but as we want to return
1208
- * negative errors, we only have a signed return value here. Any additional
1209
- * entries will lead to -EINVAL. */
1210
- for (i = 0; i < INT_MAX; i++) {
1211
- QObject *subqobj;
1212
- int subqdict_entries;
1213
- char *prefix = g_strdup_printf("%s%u.", subqdict, i);
1214
-
1215
- subqdict_entries = qdict_count_prefixed_entries(src, prefix);
1216
-
1217
- /* Remove ending "." */
1218
- prefix[strlen(prefix) - 1] = 0;
1219
- subqobj = qdict_get(src, prefix);
1220
-
1221
- g_free(prefix);
1222
-
1223
- if (subqdict_entries < 0) {
1224
- return subqdict_entries;
1225
- }
1226
-
1227
- /* There may be either a single subordinate object (named "%u") or
1228
- * multiple objects (each with a key prefixed "%u."), but not both. */
1229
- if (subqobj && subqdict_entries) {
1230
- return -EINVAL;
1231
- } else if (!subqobj && !subqdict_entries) {
1232
- break;
1233
- }
1234
-
1235
- entries += subqdict_entries ? subqdict_entries : 1;
1236
- }
1237
-
1238
- /* Consider everything handled that isn't part of the given sub-QDict */
1239
- for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
1240
- if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
1241
- entries++;
1242
- }
1243
- }
1244
-
1245
- /* Anything left in the sub-QDict that wasn't handled? */
1246
- if (qdict_size(src) != entries) {
1247
- return -EINVAL;
1248
- }
1249
-
1250
- return i;
1251
-}
1252
-
1253
-/**
1254
- * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
1255
- * elements from src to dest.
1256
- *
1257
- * If an element from src has a key already present in dest, it will not be
1258
- * moved unless overwrite is true.
1259
- *
1260
- * If overwrite is true, the conflicting values in dest will be discarded and
1261
- * replaced by the corresponding values from src.
1262
- *
1263
- * Therefore, with overwrite being true, the src QDict will always be empty when
1264
- * this function returns. If overwrite is false, the src QDict will be empty
1265
- * iff there were no conflicts.
1266
- */
1267
-void qdict_join(QDict *dest, QDict *src, bool overwrite)
1268
-{
1269
- const QDictEntry *entry, *next;
1270
-
1271
- entry = qdict_first(src);
1272
- while (entry) {
1273
- next = qdict_next(src, entry);
1274
-
1275
- if (overwrite || !qdict_haskey(dest, entry->key)) {
1276
- qdict_put_obj(dest, entry->key, qobject_ref(entry->value));
1277
- qdict_del(src, entry->key);
1278
- }
1279
-
1280
- entry = next;
1281
- }
1282
-}
1283
-
1284
-/**
1285
- * qdict_rename_keys(): Rename keys in qdict according to the replacements
1286
- * specified in the array renames. The array must be terminated by an entry
1287
- * with from = NULL.
1288
- *
1289
- * The renames are performed individually in the order of the array, so entries
1290
- * may be renamed multiple times and may or may not conflict depending on the
1291
- * order of the renames array.
1292
- *
1293
- * Returns true for success, false in error cases.
1294
- */
1295
-bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
1296
-{
1297
- QObject *qobj;
1298
-
1299
- while (renames->from) {
1300
- if (qdict_haskey(qdict, renames->from)) {
1301
- if (qdict_haskey(qdict, renames->to)) {
1302
- error_setg(errp, "'%s' and its alias '%s' can't be used at the "
1303
- "same time", renames->to, renames->from);
1304
- return false;
1305
- }
1306
-
1307
- qobj = qdict_get(qdict, renames->from);
1308
- qdict_put_obj(qdict, renames->to, qobject_ref(qobj));
1309
- qdict_del(qdict, renames->from);
1310
- }
1311
-
1312
- renames++;
1313
- }
1314
- return true;
1315
-}
1316
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
1317
new file mode 100644
1318
index XXXXXXX..XXXXXXX
1319
--- /dev/null
1320
+++ b/tests/check-block-qdict.c
1321
@@ -XXX,XX +XXX,XX @@
1322
+/*
1323
+ * Unit-tests for Block layer QDict extras
1324
+ *
1325
+ * Copyright (c) 2013-2018 Red Hat, Inc.
1326
+ *
1327
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
1328
+ * See the COPYING.LIB file in the top-level directory.
1329
+ */
1330
+
1331
+#include "qemu/osdep.h"
1332
+#include "block/qdict.h"
1333
+#include "qapi/qmp/qlist.h"
1334
+#include "qapi/qmp/qnum.h"
1335
+#include "qapi/error.h"
1336
+
1337
+static void qdict_defaults_test(void)
1338
+{
1339
+ QDict *dict, *copy;
1340
+
1341
+ dict = qdict_new();
1342
+ copy = qdict_new();
1343
+
1344
+ qdict_set_default_str(dict, "foo", "abc");
1345
+ qdict_set_default_str(dict, "foo", "def");
1346
+ g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc");
1347
+ qdict_set_default_str(dict, "bar", "ghi");
1348
+
1349
+ qdict_copy_default(copy, dict, "foo");
1350
+ g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc");
1351
+ qdict_set_default_str(copy, "bar", "xyz");
1352
+ qdict_copy_default(copy, dict, "bar");
1353
+ g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz");
1354
+
1355
+ qobject_unref(copy);
1356
+ qobject_unref(dict);
1357
+}
1358
+
1359
+static void qdict_flatten_test(void)
1360
+{
1361
+ QList *list1 = qlist_new();
1362
+ QList *list2 = qlist_new();
1363
+ QDict *dict1 = qdict_new();
1364
+ QDict *dict2 = qdict_new();
1365
+ QDict *dict3 = qdict_new();
1366
+
1367
+ /*
1368
+ * Test the flattening of
1369
+ *
1370
+ * {
1371
+ * "e": [
1372
+ * 42,
1373
+ * [
1374
+ * 23,
1375
+ * 66,
1376
+ * {
1377
+ * "a": 0,
1378
+ * "b": 1
1379
+ * }
1380
+ * ]
1381
+ * ],
1382
+ * "f": {
1383
+ * "c": 2,
1384
+ * "d": 3,
1385
+ * },
1386
+ * "g": 4
1387
+ * }
1388
+ *
1389
+ * to
1390
+ *
1391
+ * {
1392
+ * "e.0": 42,
1393
+ * "e.1.0": 23,
1394
+ * "e.1.1": 66,
1395
+ * "e.1.2.a": 0,
1396
+ * "e.1.2.b": 1,
1397
+ * "f.c": 2,
1398
+ * "f.d": 3,
1399
+ * "g": 4
1400
+ * }
1401
+ */
1402
+
1403
+ qdict_put_int(dict1, "a", 0);
1404
+ qdict_put_int(dict1, "b", 1);
1405
+
1406
+ qlist_append_int(list1, 23);
1407
+ qlist_append_int(list1, 66);
1408
+ qlist_append(list1, dict1);
1409
+ qlist_append_int(list2, 42);
1410
+ qlist_append(list2, list1);
1411
+
1412
+ qdict_put_int(dict2, "c", 2);
1413
+ qdict_put_int(dict2, "d", 3);
1414
+ qdict_put(dict3, "e", list2);
1415
+ qdict_put(dict3, "f", dict2);
1416
+ qdict_put_int(dict3, "g", 4);
1417
+
1418
+ qdict_flatten(dict3);
1419
+
1420
+ g_assert(qdict_get_int(dict3, "e.0") == 42);
1421
+ g_assert(qdict_get_int(dict3, "e.1.0") == 23);
1422
+ g_assert(qdict_get_int(dict3, "e.1.1") == 66);
1423
+ g_assert(qdict_get_int(dict3, "e.1.2.a") == 0);
1424
+ g_assert(qdict_get_int(dict3, "e.1.2.b") == 1);
1425
+ g_assert(qdict_get_int(dict3, "f.c") == 2);
1426
+ g_assert(qdict_get_int(dict3, "f.d") == 3);
1427
+ g_assert(qdict_get_int(dict3, "g") == 4);
1428
+
1429
+ g_assert(qdict_size(dict3) == 8);
1430
+
1431
+ qobject_unref(dict3);
1432
+}
1433
+
1434
+static void qdict_array_split_test(void)
1435
+{
1436
+ QDict *test_dict = qdict_new();
1437
+ QDict *dict1, *dict2;
1438
+ QNum *int1;
1439
+ QList *test_list;
1440
+
1441
+ /*
1442
+ * Test the split of
1443
+ *
1444
+ * {
1445
+ * "1.x": 0,
1446
+ * "4.y": 1,
1447
+ * "0.a": 42,
1448
+ * "o.o": 7,
1449
+ * "0.b": 23,
1450
+ * "2": 66
1451
+ * }
1452
+ *
1453
+ * to
1454
+ *
1455
+ * [
1456
+ * {
1457
+ * "a": 42,
1458
+ * "b": 23
1459
+ * },
1460
+ * {
1461
+ * "x": 0
1462
+ * },
1463
+ * 66
1464
+ * ]
1465
+ *
1466
+ * and
1467
+ *
1468
+ * {
1469
+ * "4.y": 1,
1470
+ * "o.o": 7
1471
+ * }
1472
+ *
1473
+ * (remaining in the old QDict)
1474
+ *
1475
+ * This example is given in the comment of qdict_array_split().
1476
+ */
1477
+
1478
+ qdict_put_int(test_dict, "1.x", 0);
1479
+ qdict_put_int(test_dict, "4.y", 1);
1480
+ qdict_put_int(test_dict, "0.a", 42);
1481
+ qdict_put_int(test_dict, "o.o", 7);
1482
+ qdict_put_int(test_dict, "0.b", 23);
1483
+ qdict_put_int(test_dict, "2", 66);
1484
+
1485
+ qdict_array_split(test_dict, &test_list);
1486
+
1487
+ dict1 = qobject_to(QDict, qlist_pop(test_list));
1488
+ dict2 = qobject_to(QDict, qlist_pop(test_list));
1489
+ int1 = qobject_to(QNum, qlist_pop(test_list));
1490
+
1491
+ g_assert(dict1);
1492
+ g_assert(dict2);
1493
+ g_assert(int1);
1494
+ g_assert(qlist_empty(test_list));
1495
+
1496
+ qobject_unref(test_list);
1497
+
1498
+ g_assert(qdict_get_int(dict1, "a") == 42);
1499
+ g_assert(qdict_get_int(dict1, "b") == 23);
1500
+
1501
+ g_assert(qdict_size(dict1) == 2);
1502
+
1503
+ qobject_unref(dict1);
1504
+
1505
+ g_assert(qdict_get_int(dict2, "x") == 0);
1506
+
1507
+ g_assert(qdict_size(dict2) == 1);
1508
+
1509
+ qobject_unref(dict2);
1510
+
1511
+ g_assert_cmpint(qnum_get_int(int1), ==, 66);
1512
+
1513
+ qobject_unref(int1);
1514
+
1515
+ g_assert(qdict_get_int(test_dict, "4.y") == 1);
1516
+ g_assert(qdict_get_int(test_dict, "o.o") == 7);
1517
+
1518
+ g_assert(qdict_size(test_dict) == 2);
1519
+
1520
+ qobject_unref(test_dict);
1521
+
1522
+ /*
1523
+ * Test the split of
1524
+ *
1525
+ * {
1526
+ * "0": 42,
1527
+ * "1": 23,
1528
+ * "1.x": 84
1529
+ * }
1530
+ *
1531
+ * to
1532
+ *
1533
+ * [
1534
+ * 42
1535
+ * ]
1536
+ *
1537
+ * and
1538
+ *
1539
+ * {
1540
+ * "1": 23,
1541
+ * "1.x": 84
1542
+ * }
1543
+ *
1544
+ * That is, test whether splitting stops if there is both an entry with key
1545
+ * of "%u" and other entries with keys prefixed "%u." for the same index.
1546
+ */
1547
+
1548
+ test_dict = qdict_new();
1549
+
1550
+ qdict_put_int(test_dict, "0", 42);
1551
+ qdict_put_int(test_dict, "1", 23);
1552
+ qdict_put_int(test_dict, "1.x", 84);
1553
+
1554
+ qdict_array_split(test_dict, &test_list);
1555
+
1556
+ int1 = qobject_to(QNum, qlist_pop(test_list));
1557
+
1558
+ g_assert(int1);
1559
+ g_assert(qlist_empty(test_list));
1560
+
1561
+ qobject_unref(test_list);
1562
+
1563
+ g_assert_cmpint(qnum_get_int(int1), ==, 42);
1564
+
1565
+ qobject_unref(int1);
1566
+
1567
+ g_assert(qdict_get_int(test_dict, "1") == 23);
1568
+ g_assert(qdict_get_int(test_dict, "1.x") == 84);
1569
+
1570
+ g_assert(qdict_size(test_dict) == 2);
1571
+
1572
+ qobject_unref(test_dict);
1573
+}
1574
+
1575
+static void qdict_array_entries_test(void)
1576
+{
1577
+ QDict *dict = qdict_new();
1578
+
1579
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
1580
+
1581
+ qdict_put_int(dict, "bar", 0);
1582
+ qdict_put_int(dict, "baz.0", 0);
1583
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
1584
+
1585
+ qdict_put_int(dict, "foo.1", 0);
1586
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
1587
+ qdict_put_int(dict, "foo.0", 0);
1588
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2);
1589
+ qdict_put_int(dict, "foo.bar", 0);
1590
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
1591
+ qdict_del(dict, "foo.bar");
1592
+
1593
+ qdict_put_int(dict, "foo.2.a", 0);
1594
+ qdict_put_int(dict, "foo.2.b", 0);
1595
+ qdict_put_int(dict, "foo.2.c", 0);
1596
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3);
1597
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
1598
+
1599
+ qobject_unref(dict);
1600
+
1601
+ dict = qdict_new();
1602
+ qdict_put_int(dict, "1", 0);
1603
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
1604
+ qdict_put_int(dict, "0", 0);
1605
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2);
1606
+ qdict_put_int(dict, "bar", 0);
1607
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
1608
+ qdict_del(dict, "bar");
1609
+
1610
+ qdict_put_int(dict, "2.a", 0);
1611
+ qdict_put_int(dict, "2.b", 0);
1612
+ qdict_put_int(dict, "2.c", 0);
1613
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3);
1614
+
1615
+ qobject_unref(dict);
1616
+}
1617
+
1618
+static void qdict_join_test(void)
1619
+{
1620
+ QDict *dict1, *dict2;
1621
+ bool overwrite = false;
1622
+ int i;
1623
+
1624
+ dict1 = qdict_new();
1625
+ dict2 = qdict_new();
1626
+
1627
+ /* Test everything once without overwrite and once with */
1628
+ do {
1629
+ /* Test empty dicts */
1630
+ qdict_join(dict1, dict2, overwrite);
1631
+
1632
+ g_assert(qdict_size(dict1) == 0);
1633
+ g_assert(qdict_size(dict2) == 0);
1634
+
1635
+ /* First iteration: Test movement */
1636
+ /* Second iteration: Test empty source and non-empty destination */
1637
+ qdict_put_int(dict2, "foo", 42);
1638
+
1639
+ for (i = 0; i < 2; i++) {
1640
+ qdict_join(dict1, dict2, overwrite);
1641
+
1642
+ g_assert(qdict_size(dict1) == 1);
1643
+ g_assert(qdict_size(dict2) == 0);
1644
+
1645
+ g_assert(qdict_get_int(dict1, "foo") == 42);
1646
+ }
1647
+
1648
+ /* Test non-empty source and destination without conflict */
1649
+ qdict_put_int(dict2, "bar", 23);
1650
+
1651
+ qdict_join(dict1, dict2, overwrite);
1652
+
1653
+ g_assert(qdict_size(dict1) == 2);
1654
+ g_assert(qdict_size(dict2) == 0);
1655
+
1656
+ g_assert(qdict_get_int(dict1, "foo") == 42);
1657
+ g_assert(qdict_get_int(dict1, "bar") == 23);
1658
+
1659
+ /* Test conflict */
1660
+ qdict_put_int(dict2, "foo", 84);
1661
+
1662
+ qdict_join(dict1, dict2, overwrite);
1663
+
1664
+ g_assert(qdict_size(dict1) == 2);
1665
+ g_assert(qdict_size(dict2) == !overwrite);
1666
+
1667
+ g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42));
1668
+ g_assert(qdict_get_int(dict1, "bar") == 23);
1669
+
1670
+ if (!overwrite) {
1671
+ g_assert(qdict_get_int(dict2, "foo") == 84);
1672
+ }
1673
+
1674
+ /* Check the references */
1675
+ g_assert(qdict_get(dict1, "foo")->base.refcnt == 1);
1676
+ g_assert(qdict_get(dict1, "bar")->base.refcnt == 1);
1677
+
1678
+ if (!overwrite) {
1679
+ g_assert(qdict_get(dict2, "foo")->base.refcnt == 1);
1680
+ }
1681
+
1682
+ /* Clean up */
1683
+ qdict_del(dict1, "foo");
1684
+ qdict_del(dict1, "bar");
1685
+
1686
+ if (!overwrite) {
1687
+ qdict_del(dict2, "foo");
1688
+ }
1689
+ } while (overwrite ^= true);
1690
+
1691
+ qobject_unref(dict1);
1692
+ qobject_unref(dict2);
1693
+}
1694
+
1695
+static void qdict_crumple_test_recursive(void)
1696
+{
1697
+ QDict *src, *dst, *rule, *vnc, *acl, *listen;
1698
+ QList *rules;
1699
+
1700
+ src = qdict_new();
1701
+ qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
1702
+ qdict_put_str(src, "vnc.listen.port", "5901");
1703
+ qdict_put_str(src, "vnc.acl.rules.0.match", "fred");
1704
+ qdict_put_str(src, "vnc.acl.rules.0.policy", "allow");
1705
+ qdict_put_str(src, "vnc.acl.rules.1.match", "bob");
1706
+ qdict_put_str(src, "vnc.acl.rules.1.policy", "deny");
1707
+ qdict_put_str(src, "vnc.acl.default", "deny");
1708
+ qdict_put_str(src, "vnc.acl..name", "acl0");
1709
+ qdict_put_str(src, "vnc.acl.rule..name", "acl0");
1710
+
1711
+ dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
1712
+ g_assert(dst);
1713
+ g_assert_cmpint(qdict_size(dst), ==, 1);
1714
+
1715
+ vnc = qdict_get_qdict(dst, "vnc");
1716
+ g_assert(vnc);
1717
+ g_assert_cmpint(qdict_size(vnc), ==, 3);
1718
+
1719
+ listen = qdict_get_qdict(vnc, "listen");
1720
+ g_assert(listen);
1721
+ g_assert_cmpint(qdict_size(listen), ==, 2);
1722
+ g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr"));
1723
+ g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port"));
1724
+
1725
+ acl = qdict_get_qdict(vnc, "acl");
1726
+ g_assert(acl);
1727
+ g_assert_cmpint(qdict_size(acl), ==, 3);
1728
+
1729
+ rules = qdict_get_qlist(acl, "rules");
1730
+ g_assert(rules);
1731
+ g_assert_cmpint(qlist_size(rules), ==, 2);
1732
+
1733
+ rule = qobject_to(QDict, qlist_pop(rules));
1734
+ g_assert(rule);
1735
+ g_assert_cmpint(qdict_size(rule), ==, 2);
1736
+ g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match"));
1737
+ g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy"));
1738
+ qobject_unref(rule);
1739
+
1740
+ rule = qobject_to(QDict, qlist_pop(rules));
1741
+ g_assert(rule);
1742
+ g_assert_cmpint(qdict_size(rule), ==, 2);
1743
+ g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match"));
1744
+ g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy"));
1745
+ qobject_unref(rule);
1746
+
1747
+ /* With recursive crumpling, we should see all names unescaped */
1748
+ g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
1749
+ g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
1750
+
1751
+ qobject_unref(src);
1752
+ qobject_unref(dst);
1753
+}
1754
+
1755
+static void qdict_crumple_test_empty(void)
1756
+{
1757
+ QDict *src, *dst;
1758
+
1759
+ src = qdict_new();
1760
+
1761
+ dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
1762
+
1763
+ g_assert_cmpint(qdict_size(dst), ==, 0);
1764
+
1765
+ qobject_unref(src);
1766
+ qobject_unref(dst);
1767
+}
1768
+
1769
+static int qdict_count_entries(QDict *dict)
1770
+{
1771
+ const QDictEntry *e;
1772
+ int count = 0;
1773
+
1774
+ for (e = qdict_first(dict); e; e = qdict_next(dict, e)) {
1775
+ count++;
1776
+ }
1777
+
1778
+ return count;
1779
+}
1780
+
1781
+static void qdict_rename_keys_test(void)
1782
+{
1783
+ QDict *dict = qdict_new();
1784
+ QDict *copy;
1785
+ QDictRenames *renames;
1786
+ Error *local_err = NULL;
1787
+
1788
+ qdict_put_str(dict, "abc", "foo");
1789
+ qdict_put_str(dict, "abcdef", "bar");
1790
+ qdict_put_int(dict, "number", 42);
1791
+ qdict_put_bool(dict, "flag", true);
1792
+ qdict_put_null(dict, "nothing");
1793
+
1794
+ /* Empty rename list */
1795
+ renames = (QDictRenames[]) {
1796
+ { NULL, "this can be anything" }
1797
+ };
1798
+ copy = qdict_clone_shallow(dict);
1799
+ qdict_rename_keys(copy, renames, &error_abort);
1800
+
1801
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
1802
+ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
1803
+ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
1804
+ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
1805
+ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
1806
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
1807
+
1808
+ qobject_unref(copy);
1809
+
1810
+ /* Simple rename of all entries */
1811
+ renames = (QDictRenames[]) {
1812
+ { "abc", "str1" },
1813
+ { "abcdef", "str2" },
1814
+ { "number", "int" },
1815
+ { "flag", "bool" },
1816
+ { "nothing", "null" },
1817
+ { NULL , NULL }
1818
+ };
1819
+ copy = qdict_clone_shallow(dict);
1820
+ qdict_rename_keys(copy, renames, &error_abort);
1821
+
1822
+ g_assert(!qdict_haskey(copy, "abc"));
1823
+ g_assert(!qdict_haskey(copy, "abcdef"));
1824
+ g_assert(!qdict_haskey(copy, "number"));
1825
+ g_assert(!qdict_haskey(copy, "flag"));
1826
+ g_assert(!qdict_haskey(copy, "nothing"));
1827
+
1828
+ g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
1829
+ g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
1830
+ g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
1831
+ g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
1832
+ g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
1833
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
1834
+
1835
+ qobject_unref(copy);
1836
+
1837
+ /* Renames are processed top to bottom */
1838
+ renames = (QDictRenames[]) {
1839
+ { "abc", "tmp" },
1840
+ { "abcdef", "abc" },
1841
+ { "number", "abcdef" },
1842
+ { "flag", "number" },
1843
+ { "nothing", "flag" },
1844
+ { "tmp", "nothing" },
1845
+ { NULL , NULL }
1846
+ };
1847
+ copy = qdict_clone_shallow(dict);
1848
+ qdict_rename_keys(copy, renames, &error_abort);
1849
+
1850
+ g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
1851
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
1852
+ g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
1853
+ g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
1854
+ g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
1855
+ g_assert(!qdict_haskey(copy, "tmp"));
1856
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
1857
+
1858
+ qobject_unref(copy);
1859
+
1860
+ /* Conflicting rename */
1861
+ renames = (QDictRenames[]) {
1862
+ { "abcdef", "abc" },
1863
+ { NULL , NULL }
1864
+ };
1865
+ copy = qdict_clone_shallow(dict);
1866
+ qdict_rename_keys(copy, renames, &local_err);
1867
+
1868
+ g_assert(local_err != NULL);
1869
+ error_free(local_err);
1870
+ local_err = NULL;
1871
+
1872
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
1873
+ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
1874
+ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
1875
+ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
1876
+ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
1877
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
1878
+
1879
+ qobject_unref(copy);
1880
+
1881
+ /* Renames in an empty dict */
1882
+ renames = (QDictRenames[]) {
1883
+ { "abcdef", "abc" },
1884
+ { NULL , NULL }
1885
+ };
1886
+
1887
+ qobject_unref(dict);
1888
+ dict = qdict_new();
1889
+
1890
+ qdict_rename_keys(dict, renames, &error_abort);
1891
+ g_assert(qdict_first(dict) == NULL);
1892
+
1893
+ qobject_unref(dict);
1894
+}
1895
+
1896
+static void qdict_crumple_test_bad_inputs(void)
1897
+{
1898
+ QDict *src;
1899
+ Error *error = NULL;
1900
+
1901
+ src = qdict_new();
1902
+ /* rule.0 can't be both a string and a dict */
1903
+ qdict_put_str(src, "rule.0", "fred");
1904
+ qdict_put_str(src, "rule.0.policy", "allow");
1905
+
1906
+ g_assert(qdict_crumple(src, &error) == NULL);
1907
+ g_assert(error != NULL);
1908
+ error_free(error);
1909
+ error = NULL;
1910
+ qobject_unref(src);
1911
+
1912
+ src = qdict_new();
1913
+ /* rule can't be both a list and a dict */
1914
+ qdict_put_str(src, "rule.0", "fred");
1915
+ qdict_put_str(src, "rule.a", "allow");
1916
+
1917
+ g_assert(qdict_crumple(src, &error) == NULL);
1918
+ g_assert(error != NULL);
1919
+ error_free(error);
1920
+ error = NULL;
1921
+ qobject_unref(src);
1922
+
1923
+ src = qdict_new();
1924
+ /* The input should be flat, ie no dicts or lists */
1925
+ qdict_put(src, "rule.a", qdict_new());
1926
+ qdict_put_str(src, "rule.b", "allow");
1927
+
1928
+ g_assert(qdict_crumple(src, &error) == NULL);
1929
+ g_assert(error != NULL);
1930
+ error_free(error);
1931
+ error = NULL;
1932
+ qobject_unref(src);
1933
+
1934
+ src = qdict_new();
1935
+ /* List indexes must not have gaps */
1936
+ qdict_put_str(src, "rule.0", "deny");
1937
+ qdict_put_str(src, "rule.3", "allow");
1938
+
1939
+ g_assert(qdict_crumple(src, &error) == NULL);
1940
+ g_assert(error != NULL);
1941
+ error_free(error);
1942
+ error = NULL;
1943
+ qobject_unref(src);
1944
+
1945
+ src = qdict_new();
1946
+ /* List indexes must be in %zu format */
1947
+ qdict_put_str(src, "rule.0", "deny");
1948
+ qdict_put_str(src, "rule.+1", "allow");
1949
+
1950
+ g_assert(qdict_crumple(src, &error) == NULL);
1951
+ g_assert(error != NULL);
1952
+ error_free(error);
1953
+ error = NULL;
1954
+ qobject_unref(src);
1955
+}
1956
+
1957
+int main(int argc, char **argv)
1958
+{
1959
+ g_test_init(&argc, &argv, NULL);
1960
+
1961
+ g_test_add_func("/public/defaults", qdict_defaults_test);
1962
+ g_test_add_func("/public/flatten", qdict_flatten_test);
1963
+ g_test_add_func("/public/array_split", qdict_array_split_test);
1964
+ g_test_add_func("/public/array_entries", qdict_array_entries_test);
1965
+ g_test_add_func("/public/join", qdict_join_test);
1966
+ g_test_add_func("/public/crumple/recursive",
1967
+ qdict_crumple_test_recursive);
1968
+ g_test_add_func("/public/crumple/empty",
1969
+ qdict_crumple_test_empty);
1970
+ g_test_add_func("/public/crumple/bad_inputs",
1971
+ qdict_crumple_test_bad_inputs);
1972
+
1973
+ g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
1974
+
1975
+ return g_test_run();
1976
+}
1977
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
1978
index XXXXXXX..XXXXXXX 100644
1979
--- a/tests/check-qdict.c
1980
+++ b/tests/check-qdict.c
1981
@@ -XXX,XX +XXX,XX @@
1982
*/
1983
1984
#include "qemu/osdep.h"
1985
-#include "block/qdict.h"
1986
#include "qapi/qmp/qdict.h"
1987
-#include "qapi/qmp/qlist.h"
1988
-#include "qapi/qmp/qnum.h"
1989
-#include "qapi/qmp/qstring.h"
1990
-#include "qapi/error.h"
1991
-#include "qemu-common.h"
1992
1993
/*
1994
* Public Interface test-cases
1995
@@ -XXX,XX +XXX,XX @@ static void qdict_get_try_str_test(void)
1996
qobject_unref(tests_dict);
1997
}
1998
1999
-static void qdict_defaults_test(void)
2000
-{
2001
- QDict *dict, *copy;
2002
-
2003
- dict = qdict_new();
2004
- copy = qdict_new();
2005
-
2006
- qdict_set_default_str(dict, "foo", "abc");
2007
- qdict_set_default_str(dict, "foo", "def");
2008
- g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc");
2009
- qdict_set_default_str(dict, "bar", "ghi");
2010
-
2011
- qdict_copy_default(copy, dict, "foo");
2012
- g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc");
2013
- qdict_set_default_str(copy, "bar", "xyz");
2014
- qdict_copy_default(copy, dict, "bar");
2015
- g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz");
2016
-
2017
- qobject_unref(copy);
2018
- qobject_unref(dict);
2019
-}
2020
-
2021
static void qdict_haskey_not_test(void)
2022
{
2023
QDict *tests_dict = qdict_new();
2024
@@ -XXX,XX +XXX,XX @@ static void qdict_iterapi_test(void)
2025
qobject_unref(tests_dict);
2026
}
2027
2028
-static void qdict_flatten_test(void)
2029
-{
2030
- QList *list1 = qlist_new();
2031
- QList *list2 = qlist_new();
2032
- QDict *dict1 = qdict_new();
2033
- QDict *dict2 = qdict_new();
2034
- QDict *dict3 = qdict_new();
2035
-
2036
- /*
2037
- * Test the flattening of
2038
- *
2039
- * {
2040
- * "e": [
2041
- * 42,
2042
- * [
2043
- * 23,
2044
- * 66,
2045
- * {
2046
- * "a": 0,
2047
- * "b": 1
2048
- * }
2049
- * ]
2050
- * ],
2051
- * "f": {
2052
- * "c": 2,
2053
- * "d": 3,
2054
- * },
2055
- * "g": 4
2056
- * }
2057
- *
2058
- * to
2059
- *
2060
- * {
2061
- * "e.0": 42,
2062
- * "e.1.0": 23,
2063
- * "e.1.1": 66,
2064
- * "e.1.2.a": 0,
2065
- * "e.1.2.b": 1,
2066
- * "f.c": 2,
2067
- * "f.d": 3,
2068
- * "g": 4
2069
- * }
2070
- */
2071
-
2072
- qdict_put_int(dict1, "a", 0);
2073
- qdict_put_int(dict1, "b", 1);
2074
-
2075
- qlist_append_int(list1, 23);
2076
- qlist_append_int(list1, 66);
2077
- qlist_append(list1, dict1);
2078
- qlist_append_int(list2, 42);
2079
- qlist_append(list2, list1);
2080
-
2081
- qdict_put_int(dict2, "c", 2);
2082
- qdict_put_int(dict2, "d", 3);
2083
- qdict_put(dict3, "e", list2);
2084
- qdict_put(dict3, "f", dict2);
2085
- qdict_put_int(dict3, "g", 4);
2086
-
2087
- qdict_flatten(dict3);
2088
-
2089
- g_assert(qdict_get_int(dict3, "e.0") == 42);
2090
- g_assert(qdict_get_int(dict3, "e.1.0") == 23);
2091
- g_assert(qdict_get_int(dict3, "e.1.1") == 66);
2092
- g_assert(qdict_get_int(dict3, "e.1.2.a") == 0);
2093
- g_assert(qdict_get_int(dict3, "e.1.2.b") == 1);
2094
- g_assert(qdict_get_int(dict3, "f.c") == 2);
2095
- g_assert(qdict_get_int(dict3, "f.d") == 3);
2096
- g_assert(qdict_get_int(dict3, "g") == 4);
2097
-
2098
- g_assert(qdict_size(dict3) == 8);
2099
-
2100
- qobject_unref(dict3);
2101
-}
2102
-
2103
-static void qdict_array_split_test(void)
2104
-{
2105
- QDict *test_dict = qdict_new();
2106
- QDict *dict1, *dict2;
2107
- QNum *int1;
2108
- QList *test_list;
2109
-
2110
- /*
2111
- * Test the split of
2112
- *
2113
- * {
2114
- * "1.x": 0,
2115
- * "4.y": 1,
2116
- * "0.a": 42,
2117
- * "o.o": 7,
2118
- * "0.b": 23,
2119
- * "2": 66
2120
- * }
2121
- *
2122
- * to
2123
- *
2124
- * [
2125
- * {
2126
- * "a": 42,
2127
- * "b": 23
2128
- * },
2129
- * {
2130
- * "x": 0
2131
- * },
2132
- * 66
2133
- * ]
2134
- *
2135
- * and
2136
- *
2137
- * {
2138
- * "4.y": 1,
2139
- * "o.o": 7
2140
- * }
2141
- *
2142
- * (remaining in the old QDict)
2143
- *
2144
- * This example is given in the comment of qdict_array_split().
2145
- */
2146
-
2147
- qdict_put_int(test_dict, "1.x", 0);
2148
- qdict_put_int(test_dict, "4.y", 1);
2149
- qdict_put_int(test_dict, "0.a", 42);
2150
- qdict_put_int(test_dict, "o.o", 7);
2151
- qdict_put_int(test_dict, "0.b", 23);
2152
- qdict_put_int(test_dict, "2", 66);
2153
-
2154
- qdict_array_split(test_dict, &test_list);
2155
-
2156
- dict1 = qobject_to(QDict, qlist_pop(test_list));
2157
- dict2 = qobject_to(QDict, qlist_pop(test_list));
2158
- int1 = qobject_to(QNum, qlist_pop(test_list));
2159
-
2160
- g_assert(dict1);
2161
- g_assert(dict2);
2162
- g_assert(int1);
2163
- g_assert(qlist_empty(test_list));
2164
-
2165
- qobject_unref(test_list);
2166
-
2167
- g_assert(qdict_get_int(dict1, "a") == 42);
2168
- g_assert(qdict_get_int(dict1, "b") == 23);
2169
-
2170
- g_assert(qdict_size(dict1) == 2);
2171
-
2172
- qobject_unref(dict1);
2173
-
2174
- g_assert(qdict_get_int(dict2, "x") == 0);
2175
-
2176
- g_assert(qdict_size(dict2) == 1);
2177
-
2178
- qobject_unref(dict2);
2179
-
2180
- g_assert_cmpint(qnum_get_int(int1), ==, 66);
2181
-
2182
- qobject_unref(int1);
2183
-
2184
- g_assert(qdict_get_int(test_dict, "4.y") == 1);
2185
- g_assert(qdict_get_int(test_dict, "o.o") == 7);
2186
-
2187
- g_assert(qdict_size(test_dict) == 2);
2188
-
2189
- qobject_unref(test_dict);
2190
-
2191
- /*
2192
- * Test the split of
2193
- *
2194
- * {
2195
- * "0": 42,
2196
- * "1": 23,
2197
- * "1.x": 84
2198
- * }
2199
- *
2200
- * to
2201
- *
2202
- * [
2203
- * 42
2204
- * ]
2205
- *
2206
- * and
2207
- *
2208
- * {
2209
- * "1": 23,
2210
- * "1.x": 84
2211
- * }
2212
- *
2213
- * That is, test whether splitting stops if there is both an entry with key
2214
- * of "%u" and other entries with keys prefixed "%u." for the same index.
2215
- */
2216
-
2217
- test_dict = qdict_new();
2218
-
2219
- qdict_put_int(test_dict, "0", 42);
2220
- qdict_put_int(test_dict, "1", 23);
2221
- qdict_put_int(test_dict, "1.x", 84);
2222
-
2223
- qdict_array_split(test_dict, &test_list);
2224
-
2225
- int1 = qobject_to(QNum, qlist_pop(test_list));
2226
-
2227
- g_assert(int1);
2228
- g_assert(qlist_empty(test_list));
2229
-
2230
- qobject_unref(test_list);
2231
-
2232
- g_assert_cmpint(qnum_get_int(int1), ==, 42);
2233
-
2234
- qobject_unref(int1);
2235
-
2236
- g_assert(qdict_get_int(test_dict, "1") == 23);
2237
- g_assert(qdict_get_int(test_dict, "1.x") == 84);
2238
-
2239
- g_assert(qdict_size(test_dict) == 2);
2240
-
2241
- qobject_unref(test_dict);
2242
-}
2243
-
2244
-static void qdict_array_entries_test(void)
2245
-{
2246
- QDict *dict = qdict_new();
2247
-
2248
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
2249
-
2250
- qdict_put_int(dict, "bar", 0);
2251
- qdict_put_int(dict, "baz.0", 0);
2252
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
2253
-
2254
- qdict_put_int(dict, "foo.1", 0);
2255
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
2256
- qdict_put_int(dict, "foo.0", 0);
2257
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2);
2258
- qdict_put_int(dict, "foo.bar", 0);
2259
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
2260
- qdict_del(dict, "foo.bar");
2261
-
2262
- qdict_put_int(dict, "foo.2.a", 0);
2263
- qdict_put_int(dict, "foo.2.b", 0);
2264
- qdict_put_int(dict, "foo.2.c", 0);
2265
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3);
2266
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
2267
-
2268
- qobject_unref(dict);
2269
-
2270
- dict = qdict_new();
2271
- qdict_put_int(dict, "1", 0);
2272
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
2273
- qdict_put_int(dict, "0", 0);
2274
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2);
2275
- qdict_put_int(dict, "bar", 0);
2276
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
2277
- qdict_del(dict, "bar");
2278
-
2279
- qdict_put_int(dict, "2.a", 0);
2280
- qdict_put_int(dict, "2.b", 0);
2281
- qdict_put_int(dict, "2.c", 0);
2282
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3);
2283
-
2284
- qobject_unref(dict);
2285
-}
2286
-
2287
-static void qdict_join_test(void)
2288
-{
2289
- QDict *dict1, *dict2;
2290
- bool overwrite = false;
2291
- int i;
2292
-
2293
- dict1 = qdict_new();
2294
- dict2 = qdict_new();
2295
-
2296
- /* Test everything once without overwrite and once with */
2297
- do
2298
- {
2299
- /* Test empty dicts */
2300
- qdict_join(dict1, dict2, overwrite);
2301
-
2302
- g_assert(qdict_size(dict1) == 0);
2303
- g_assert(qdict_size(dict2) == 0);
2304
-
2305
- /* First iteration: Test movement */
2306
- /* Second iteration: Test empty source and non-empty destination */
2307
- qdict_put_int(dict2, "foo", 42);
2308
-
2309
- for (i = 0; i < 2; i++) {
2310
- qdict_join(dict1, dict2, overwrite);
2311
-
2312
- g_assert(qdict_size(dict1) == 1);
2313
- g_assert(qdict_size(dict2) == 0);
2314
-
2315
- g_assert(qdict_get_int(dict1, "foo") == 42);
2316
- }
2317
-
2318
- /* Test non-empty source and destination without conflict */
2319
- qdict_put_int(dict2, "bar", 23);
2320
-
2321
- qdict_join(dict1, dict2, overwrite);
2322
-
2323
- g_assert(qdict_size(dict1) == 2);
2324
- g_assert(qdict_size(dict2) == 0);
2325
-
2326
- g_assert(qdict_get_int(dict1, "foo") == 42);
2327
- g_assert(qdict_get_int(dict1, "bar") == 23);
2328
-
2329
- /* Test conflict */
2330
- qdict_put_int(dict2, "foo", 84);
2331
-
2332
- qdict_join(dict1, dict2, overwrite);
2333
-
2334
- g_assert(qdict_size(dict1) == 2);
2335
- g_assert(qdict_size(dict2) == !overwrite);
2336
-
2337
- g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42));
2338
- g_assert(qdict_get_int(dict1, "bar") == 23);
2339
-
2340
- if (!overwrite) {
2341
- g_assert(qdict_get_int(dict2, "foo") == 84);
2342
- }
2343
-
2344
- /* Check the references */
2345
- g_assert(qdict_get(dict1, "foo")->base.refcnt == 1);
2346
- g_assert(qdict_get(dict1, "bar")->base.refcnt == 1);
2347
-
2348
- if (!overwrite) {
2349
- g_assert(qdict_get(dict2, "foo")->base.refcnt == 1);
2350
- }
2351
-
2352
- /* Clean up */
2353
- qdict_del(dict1, "foo");
2354
- qdict_del(dict1, "bar");
2355
-
2356
- if (!overwrite) {
2357
- qdict_del(dict2, "foo");
2358
- }
2359
- }
2360
- while (overwrite ^= true);
2361
-
2362
- qobject_unref(dict1);
2363
- qobject_unref(dict2);
2364
-}
2365
-
2366
-static void qdict_crumple_test_recursive(void)
2367
-{
2368
- QDict *src, *dst, *rule, *vnc, *acl, *listen;
2369
- QList *rules;
2370
-
2371
- src = qdict_new();
2372
- qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
2373
- qdict_put_str(src, "vnc.listen.port", "5901");
2374
- qdict_put_str(src, "vnc.acl.rules.0.match", "fred");
2375
- qdict_put_str(src, "vnc.acl.rules.0.policy", "allow");
2376
- qdict_put_str(src, "vnc.acl.rules.1.match", "bob");
2377
- qdict_put_str(src, "vnc.acl.rules.1.policy", "deny");
2378
- qdict_put_str(src, "vnc.acl.default", "deny");
2379
- qdict_put_str(src, "vnc.acl..name", "acl0");
2380
- qdict_put_str(src, "vnc.acl.rule..name", "acl0");
2381
-
2382
- dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
2383
- g_assert(dst);
2384
- g_assert_cmpint(qdict_size(dst), ==, 1);
2385
-
2386
- vnc = qdict_get_qdict(dst, "vnc");
2387
- g_assert(vnc);
2388
- g_assert_cmpint(qdict_size(vnc), ==, 3);
2389
-
2390
- listen = qdict_get_qdict(vnc, "listen");
2391
- g_assert(listen);
2392
- g_assert_cmpint(qdict_size(listen), ==, 2);
2393
- g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr"));
2394
- g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port"));
2395
-
2396
- acl = qdict_get_qdict(vnc, "acl");
2397
- g_assert(acl);
2398
- g_assert_cmpint(qdict_size(acl), ==, 3);
2399
-
2400
- rules = qdict_get_qlist(acl, "rules");
2401
- g_assert(rules);
2402
- g_assert_cmpint(qlist_size(rules), ==, 2);
2403
-
2404
- rule = qobject_to(QDict, qlist_pop(rules));
2405
- g_assert(rule);
2406
- g_assert_cmpint(qdict_size(rule), ==, 2);
2407
- g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match"));
2408
- g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy"));
2409
- qobject_unref(rule);
2410
-
2411
- rule = qobject_to(QDict, qlist_pop(rules));
2412
- g_assert(rule);
2413
- g_assert_cmpint(qdict_size(rule), ==, 2);
2414
- g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match"));
2415
- g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy"));
2416
- qobject_unref(rule);
2417
-
2418
- /* With recursive crumpling, we should see all names unescaped */
2419
- g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
2420
- g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
2421
-
2422
- qobject_unref(src);
2423
- qobject_unref(dst);
2424
-}
2425
-
2426
-static void qdict_crumple_test_empty(void)
2427
-{
2428
- QDict *src, *dst;
2429
-
2430
- src = qdict_new();
2431
-
2432
- dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
2433
-
2434
- g_assert_cmpint(qdict_size(dst), ==, 0);
2435
-
2436
- qobject_unref(src);
2437
- qobject_unref(dst);
2438
-}
2439
-
2440
-static int qdict_count_entries(QDict *dict)
2441
-{
2442
- const QDictEntry *e;
2443
- int count = 0;
2444
-
2445
- for (e = qdict_first(dict); e; e = qdict_next(dict, e)) {
2446
- count++;
2447
- }
2448
-
2449
- return count;
2450
-}
2451
-
2452
-static void qdict_rename_keys_test(void)
2453
-{
2454
- QDict *dict = qdict_new();
2455
- QDict *copy;
2456
- QDictRenames *renames;
2457
- Error *local_err = NULL;
2458
-
2459
- qdict_put_str(dict, "abc", "foo");
2460
- qdict_put_str(dict, "abcdef", "bar");
2461
- qdict_put_int(dict, "number", 42);
2462
- qdict_put_bool(dict, "flag", true);
2463
- qdict_put_null(dict, "nothing");
2464
-
2465
- /* Empty rename list */
2466
- renames = (QDictRenames[]) {
2467
- { NULL, "this can be anything" }
2468
- };
2469
- copy = qdict_clone_shallow(dict);
2470
- qdict_rename_keys(copy, renames, &error_abort);
2471
-
2472
- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
2473
- g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
2474
- g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
2475
- g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
2476
- g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
2477
- g_assert_cmpint(qdict_count_entries(copy), ==, 5);
2478
-
2479
- qobject_unref(copy);
2480
-
2481
- /* Simple rename of all entries */
2482
- renames = (QDictRenames[]) {
2483
- { "abc", "str1" },
2484
- { "abcdef", "str2" },
2485
- { "number", "int" },
2486
- { "flag", "bool" },
2487
- { "nothing", "null" },
2488
- { NULL , NULL }
2489
- };
2490
- copy = qdict_clone_shallow(dict);
2491
- qdict_rename_keys(copy, renames, &error_abort);
2492
-
2493
- g_assert(!qdict_haskey(copy, "abc"));
2494
- g_assert(!qdict_haskey(copy, "abcdef"));
2495
- g_assert(!qdict_haskey(copy, "number"));
2496
- g_assert(!qdict_haskey(copy, "flag"));
2497
- g_assert(!qdict_haskey(copy, "nothing"));
2498
-
2499
- g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
2500
- g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
2501
- g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
2502
- g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
2503
- g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
2504
- g_assert_cmpint(qdict_count_entries(copy), ==, 5);
2505
-
2506
- qobject_unref(copy);
2507
-
2508
- /* Renames are processed top to bottom */
2509
- renames = (QDictRenames[]) {
2510
- { "abc", "tmp" },
2511
- { "abcdef", "abc" },
2512
- { "number", "abcdef" },
2513
- { "flag", "number" },
2514
- { "nothing", "flag" },
2515
- { "tmp", "nothing" },
2516
- { NULL , NULL }
2517
- };
2518
- copy = qdict_clone_shallow(dict);
2519
- qdict_rename_keys(copy, renames, &error_abort);
2520
-
2521
- g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
2522
- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
2523
- g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
2524
- g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
2525
- g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
2526
- g_assert(!qdict_haskey(copy, "tmp"));
2527
- g_assert_cmpint(qdict_count_entries(copy), ==, 5);
2528
-
2529
- qobject_unref(copy);
2530
-
2531
- /* Conflicting rename */
2532
- renames = (QDictRenames[]) {
2533
- { "abcdef", "abc" },
2534
- { NULL , NULL }
2535
- };
2536
- copy = qdict_clone_shallow(dict);
2537
- qdict_rename_keys(copy, renames, &local_err);
2538
-
2539
- g_assert(local_err != NULL);
2540
- error_free(local_err);
2541
- local_err = NULL;
2542
-
2543
- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
2544
- g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
2545
- g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
2546
- g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
2547
- g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
2548
- g_assert_cmpint(qdict_count_entries(copy), ==, 5);
2549
-
2550
- qobject_unref(copy);
2551
-
2552
- /* Renames in an empty dict */
2553
- renames = (QDictRenames[]) {
2554
- { "abcdef", "abc" },
2555
- { NULL , NULL }
2556
- };
2557
-
2558
- qobject_unref(dict);
2559
- dict = qdict_new();
2560
-
2561
- qdict_rename_keys(dict, renames, &error_abort);
2562
- g_assert(qdict_first(dict) == NULL);
2563
-
2564
- qobject_unref(dict);
2565
-}
2566
-
2567
-static void qdict_crumple_test_bad_inputs(void)
2568
-{
2569
- QDict *src;
2570
- Error *error = NULL;
2571
-
2572
- src = qdict_new();
2573
- /* rule.0 can't be both a string and a dict */
2574
- qdict_put_str(src, "rule.0", "fred");
2575
- qdict_put_str(src, "rule.0.policy", "allow");
2576
-
2577
- g_assert(qdict_crumple(src, &error) == NULL);
2578
- g_assert(error != NULL);
2579
- error_free(error);
2580
- error = NULL;
2581
- qobject_unref(src);
2582
-
2583
- src = qdict_new();
2584
- /* rule can't be both a list and a dict */
2585
- qdict_put_str(src, "rule.0", "fred");
2586
- qdict_put_str(src, "rule.a", "allow");
2587
-
2588
- g_assert(qdict_crumple(src, &error) == NULL);
2589
- g_assert(error != NULL);
2590
- error_free(error);
2591
- error = NULL;
2592
- qobject_unref(src);
2593
-
2594
- src = qdict_new();
2595
- /* The input should be flat, ie no dicts or lists */
2596
- qdict_put(src, "rule.a", qdict_new());
2597
- qdict_put_str(src, "rule.b", "allow");
2598
-
2599
- g_assert(qdict_crumple(src, &error) == NULL);
2600
- g_assert(error != NULL);
2601
- error_free(error);
2602
- error = NULL;
2603
- qobject_unref(src);
2604
-
2605
- src = qdict_new();
2606
- /* List indexes must not have gaps */
2607
- qdict_put_str(src, "rule.0", "deny");
2608
- qdict_put_str(src, "rule.3", "allow");
2609
-
2610
- g_assert(qdict_crumple(src, &error) == NULL);
2611
- g_assert(error != NULL);
2612
- error_free(error);
2613
- error = NULL;
2614
- qobject_unref(src);
2615
-
2616
- src = qdict_new();
2617
- /* List indexes must be in %zu format */
2618
- qdict_put_str(src, "rule.0", "deny");
2619
- qdict_put_str(src, "rule.+1", "allow");
2620
-
2621
- g_assert(qdict_crumple(src, &error) == NULL);
2622
- g_assert(error != NULL);
2623
- error_free(error);
2624
- error = NULL;
2625
- qobject_unref(src);
2626
-}
2627
-
2628
/*
2629
* Errors test-cases
2630
*/
2631
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
2632
g_test_add_func("/public/get_try_int", qdict_get_try_int_test);
2633
g_test_add_func("/public/get_str", qdict_get_str_test);
2634
g_test_add_func("/public/get_try_str", qdict_get_try_str_test);
2635
- g_test_add_func("/public/defaults", qdict_defaults_test);
2636
g_test_add_func("/public/haskey_not", qdict_haskey_not_test);
2637
g_test_add_func("/public/haskey", qdict_haskey_test);
2638
g_test_add_func("/public/del", qdict_del_test);
2639
g_test_add_func("/public/to_qdict", qobject_to_qdict_test);
2640
g_test_add_func("/public/iterapi", qdict_iterapi_test);
2641
- g_test_add_func("/public/flatten", qdict_flatten_test);
2642
- g_test_add_func("/public/array_split", qdict_array_split_test);
2643
- g_test_add_func("/public/array_entries", qdict_array_entries_test);
2644
- g_test_add_func("/public/join", qdict_join_test);
2645
2646
g_test_add_func("/errors/put_exists", qdict_put_exists_test);
2647
g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
2648
2649
- g_test_add_func("/public/crumple/recursive",
2650
- qdict_crumple_test_recursive);
2651
- g_test_add_func("/public/crumple/empty",
2652
- qdict_crumple_test_empty);
2653
- g_test_add_func("/public/crumple/bad_inputs",
2654
- qdict_crumple_test_bad_inputs);
2655
-
2656
- g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
2657
-
2658
/* The Big one */
2659
if (g_test_slow()) {
2660
g_test_add_func("/stress/test", qdict_stress_test);
2661
diff --git a/MAINTAINERS b/MAINTAINERS
2662
index XXXXXXX..XXXXXXX 100644
2663
--- a/MAINTAINERS
2664
+++ b/MAINTAINERS
2665
@@ -XXX,XX +XXX,XX @@ F: qemu-img*
2666
F: qemu-io*
2667
F: tests/qemu-iotests/
2668
F: util/qemu-progress.c
2669
+F: qobject/block-qdict.c
2670
+F: test/check-block-qdict.c
2671
T: git git://repo.or.cz/qemu/kevin.git block
2672
2673
Block I/O path
2674
diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs
2675
index XXXXXXX..XXXXXXX 100644
2676
--- a/qobject/Makefile.objs
2677
+++ b/qobject/Makefile.objs
2678
@@ -XXX,XX +XXX,XX @@
2679
util-obj-y = qnull.o qnum.o qstring.o qdict.o qlist.o qbool.o qlit.o
2680
util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o
2681
+util-obj-y += block-qdict.o
2682
diff --git a/tests/Makefile.include b/tests/Makefile.include
2683
index XXXXXXX..XXXXXXX 100644
2684
--- a/tests/Makefile.include
2685
+++ b/tests/Makefile.include
2686
@@ -XXX,XX +XXX,XX @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
2687
2688
check-unit-y = tests/check-qdict$(EXESUF)
2689
gcov-files-check-qdict-y = qobject/qdict.c
2690
+check-unit-y = tests/check-block-qdict$(EXESUF)
2691
+gcov-files-check-block-qdict-y = qobject/block-qdict.c
2692
check-unit-y += tests/test-char$(EXESUF)
2693
gcov-files-check-qdict-y = chardev/char.c
2694
check-unit-y += tests/check-qnum$(EXESUF)
2695
@@ -XXX,XX +XXX,XX @@ GENERATED_FILES += tests/test-qapi-types.h tests/test-qapi-visit.h \
2696
test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
2697
    tests/check-qlist.o tests/check-qnull.o tests/check-qobject.o \
2698
    tests/check-qjson.o tests/check-qlit.o \
2699
+    tests/check-block-qtest.o \
2700
    tests/test-coroutine.o tests/test-string-output-visitor.o \
2701
    tests/test-string-input-visitor.o tests/test-qobject-output-visitor.o \
2702
    tests/test-clone-visitor.o \
2703
@@ -XXX,XX +XXX,XX @@ test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
2704
tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y)
2705
tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
2706
tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y)
2707
+tests/check-block-qdict$(EXESUF): tests/check-block-qdict.o $(test-util-obj-y)
2708
tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y)
2709
tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y)
2710
tests/check-qobject$(EXESUF): tests/check-qobject.o $(test-util-obj-y)
87
--
2711
--
88
1.8.3.1
2712
2.13.6
89
2713
90
2714
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
2
3
Configuration flows through the block subsystem in a rather peculiar
4
way. Configuration made with -drive enters it as QemuOpts.
5
Configuration made with -blockdev / blockdev-add enters it as QAPI
6
type BlockdevOptions. The block subsystem uses QDict, QemuOpts and
7
QAPI types internally. The precise flow is next to impossible to
8
explain (I tried for this commit message, but gave up after wasting
9
several hours). What I can explain is a flaw in the BlockDriver
10
interface that leads to this bug:
11
12
$ qemu-system-x86_64 -blockdev node-name=n1,driver=nfs,server.type=inet,server.host=localhost,path=/foo/bar,user=1234
13
qemu-system-x86_64: -blockdev node-name=n1,driver=nfs,server.type=inet,server.host=localhost,path=/foo/bar,user=1234: Internal error: parameter user invalid
14
15
QMP blockdev-add is broken the same way.
16
17
Here's what happens. The block layer passes configuration represented
18
as flat QDict (with dotted keys) to BlockDriver methods
19
.bdrv_file_open(). The QDict's members are typed according to the
20
QAPI schema.
21
22
nfs_file_open() converts it to QAPI type BlockdevOptionsNfs, with
23
qdict_crumple() and a qobject input visitor.
24
25
This visitor comes in two flavors. The plain flavor requires scalars
26
to be typed according to the QAPI schema. That's the case here. The
27
keyval flavor requires string scalars. That's not the case here.
28
nfs_file_open() uses the latter, and promptly falls apart for members
29
@user, @group, @tcp-syn-count, @readahead-size, @page-cache-size,
30
@debug.
31
32
Switching to the plain flavor would fix -blockdev, but break -drive,
33
because there the scalars arrive in nfs_file_open() as strings.
34
35
The proper fix would be to replace the QDict by QAPI type
36
BlockdevOptions in the BlockDriver interface. Sadly, that's beyond my
37
reach right now.
38
39
Next best would be to fix the block layer to always pass correctly
40
typed QDicts to the BlockDriver methods. Also beyond my reach.
41
42
What I can do is throw another hack onto the pile: have
43
nfs_file_open() convert all members to string, so use of the keyval
44
flavor actually works, by replacing qdict_crumple() by new function
45
qdict_crumple_for_keyval_qiv().
46
47
The pattern "pass result of qdict_crumple() to
48
qobject_input_visitor_new_keyval()" occurs several times more:
49
50
* qemu_rbd_open()
51
52
Same issue as nfs_file_open(), but since BlockdevOptionsRbd has only
53
string members, its only a latent bug. Fix it anyway.
54
55
* parallels_co_create_opts(), qcow_co_create_opts(),
56
qcow2_co_create_opts(), bdrv_qed_co_create_opts(),
57
sd_co_create_opts(), vhdx_co_create_opts(), vpc_co_create_opts()
58
59
These work, because they create the QDict with
60
qemu_opts_to_qdict_filtered(), which creates only string scalars.
61
The function sports a TODO comment asking for better typing; that's
62
going to be fun. Use qdict_crumple_for_keyval_qiv() to be safe.
63
64
Signed-off-by: Markus Armbruster <armbru@redhat.com>
65
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
66
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
---
67
---
4
block.c | 3 ++-
68
include/block/qdict.h | 1 +
5
block/blkdebug.c | 2 +-
69
block/nfs.c | 2 +-
6
block/block-backend.c | 2 +-
70
block/parallels.c | 2 +-
7
block/crypto.c | 2 +-
71
block/qcow.c | 2 +-
8
block/parallels.c | 8 ++++----
72
block/qcow2.c | 2 +-
9
block/qcow.c | 4 ++--
73
block/qed.c | 2 +-
10
block/qcow2-refcount.c | 2 +-
74
block/rbd.c | 2 +-
11
block/qcow2.c | 4 ++--
75
block/sheepdog.c | 2 +-
12
block/raw-format.c | 2 +-
76
block/vhdx.c | 2 +-
13
block/vhdx-log.c | 2 +-
77
block/vpc.c | 2 +-
14
block/vhdx.c | 2 +-
78
qobject/block-qdict.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
15
include/block/block.h | 2 +-
79
11 files changed, 67 insertions(+), 9 deletions(-)
16
12 files changed, 18 insertions(+), 17 deletions(-)
80
17
81
diff --git a/include/block/qdict.h b/include/block/qdict.h
18
diff --git a/block.c b/block.c
82
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
83
--- a/include/block/qdict.h
20
--- a/block.c
84
+++ b/include/block/qdict.h
21
+++ b/block.c
85
@@ -XXX,XX +XXX,XX @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
22
@@ -XXX,XX +XXX,XX @@ exit:
86
void qdict_array_split(QDict *src, QList **dst);
23
/**
87
int qdict_array_entries(QDict *src, const char *subqdict);
24
* Truncate file to 'offset' bytes (needed only for file protocols)
88
QObject *qdict_crumple(const QDict *src, Error **errp);
25
*/
89
+QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp);
26
-int bdrv_truncate(BlockDriverState *bs, int64_t offset)
90
void qdict_flatten(QDict *qdict);
27
+int bdrv_truncate(BdrvChild *child, int64_t offset)
91
28
{
92
typedef struct QDictRenames {
29
+ BlockDriverState *bs = child->bs;
93
diff --git a/block/nfs.c b/block/nfs.c
30
BlockDriver *drv = bs->drv;
94
index XXXXXXX..XXXXXXX 100644
31
int ret;
95
--- a/block/nfs.c
32
if (!drv)
96
+++ b/block/nfs.c
33
diff --git a/block/blkdebug.c b/block/blkdebug.c
97
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
34
index XXXXXXX..XXXXXXX 100644
98
const QDictEntry *e;
35
--- a/block/blkdebug.c
99
Error *local_err = NULL;
36
+++ b/block/blkdebug.c
100
37
@@ -XXX,XX +XXX,XX @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
101
- crumpled = qdict_crumple(options, errp);
38
102
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
39
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
103
if (crumpled == NULL) {
40
{
104
return NULL;
41
- return bdrv_truncate(bs->file->bs, offset);
42
+ return bdrv_truncate(bs->file, offset);
43
}
44
45
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
46
diff --git a/block/block-backend.c b/block/block-backend.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block/block-backend.c
49
+++ b/block/block-backend.c
50
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset)
51
return -ENOMEDIUM;
52
}
105
}
53
54
- return bdrv_truncate(blk_bs(blk), offset);
55
+ return bdrv_truncate(blk->root, offset);
56
}
57
58
static void blk_pdiscard_entry(void *opaque)
59
diff --git a/block/crypto.c b/block/crypto.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block/crypto.c
62
+++ b/block/crypto.c
63
@@ -XXX,XX +XXX,XX @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
64
65
offset += payload_offset;
66
67
- return bdrv_truncate(bs->file->bs, offset);
68
+ return bdrv_truncate(bs->file, offset);
69
}
70
71
static void block_crypto_close(BlockDriverState *bs)
72
diff --git a/block/parallels.c b/block/parallels.c
106
diff --git a/block/parallels.c b/block/parallels.c
73
index XXXXXXX..XXXXXXX 100644
107
index XXXXXXX..XXXXXXX 100644
74
--- a/block/parallels.c
108
--- a/block/parallels.c
75
+++ b/block/parallels.c
109
+++ b/block/parallels.c
76
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
77
s->data_end << BDRV_SECTOR_BITS,
111
qdict_put_str(qdict, "driver", "parallels");
78
space << BDRV_SECTOR_BITS, 0);
112
qdict_put_str(qdict, "file", bs->node_name);
79
} else {
113
80
- ret = bdrv_truncate(bs->file->bs,
114
- qobj = qdict_crumple(qdict, errp);
81
+ ret = bdrv_truncate(bs->file,
115
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
82
(s->data_end + space) << BDRV_SECTOR_BITS);
116
qobject_unref(qdict);
83
}
117
qdict = qobject_to(QDict, qobj);
84
if (ret < 0) {
118
if (qdict == NULL) {
85
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
86
size - res->image_end_offset);
87
res->leaks += count;
88
if (fix & BDRV_FIX_LEAKS) {
89
- ret = bdrv_truncate(bs->file->bs, res->image_end_offset);
90
+ ret = bdrv_truncate(bs->file, res->image_end_offset);
91
if (ret < 0) {
92
res->check_errors++;
93
return ret;
94
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
95
goto fail_options;
96
}
97
if (!bdrv_has_zero_init(bs->file->bs) ||
98
- bdrv_truncate(bs->file->bs, bdrv_getlength(bs->file->bs)) != 0) {
99
+ bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs)) != 0) {
100
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
101
}
102
103
@@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs)
104
}
105
106
if (bs->open_flags & BDRV_O_RDWR) {
107
- bdrv_truncate(bs->file->bs, s->data_end << BDRV_SECTOR_BITS);
108
+ bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS);
109
}
110
111
g_free(s->bat_dirty_bmap);
112
diff --git a/block/qcow.c b/block/qcow.c
119
diff --git a/block/qcow.c b/block/qcow.c
113
index XXXXXXX..XXXXXXX 100644
120
index XXXXXXX..XXXXXXX 100644
114
--- a/block/qcow.c
121
--- a/block/qcow.c
115
+++ b/block/qcow.c
122
+++ b/block/qcow.c
116
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
123
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
117
/* round to cluster size */
124
qdict_put_str(qdict, "driver", "qcow");
118
cluster_offset = (cluster_offset + s->cluster_size - 1) &
125
qdict_put_str(qdict, "file", bs->node_name);
119
~(s->cluster_size - 1);
126
120
- bdrv_truncate(bs->file->bs, cluster_offset + s->cluster_size);
127
- qobj = qdict_crumple(qdict, errp);
121
+ bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
128
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
122
/* if encrypted, we must initialize the cluster
129
qobject_unref(qdict);
123
content which won't be written */
130
qdict = qobject_to(QDict, qobj);
124
if (bs->encrypted &&
131
if (qdict == NULL) {
125
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
126
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
127
l1_length) < 0)
128
return -1;
129
- ret = bdrv_truncate(bs->file->bs, s->l1_table_offset + l1_length);
130
+ ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
131
if (ret < 0)
132
return ret;
133
134
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
135
index XXXXXXX..XXXXXXX 100644
136
--- a/block/qcow2-refcount.c
137
+++ b/block/qcow2-refcount.c
138
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
139
goto resize_fail;
140
}
141
142
- ret = bdrv_truncate(bs->file->bs, offset + s->cluster_size);
143
+ ret = bdrv_truncate(bs->file, offset + s->cluster_size);
144
if (ret < 0) {
145
goto resize_fail;
146
}
147
diff --git a/block/qcow2.c b/block/qcow2.c
132
diff --git a/block/qcow2.c b/block/qcow2.c
148
index XXXXXXX..XXXXXXX 100644
133
index XXXXXXX..XXXXXXX 100644
149
--- a/block/qcow2.c
134
--- a/block/qcow2.c
150
+++ b/block/qcow2.c
135
+++ b/block/qcow2.c
151
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
152
/* align end of file to a sector boundary to ease reading with
137
qdict_put_str(qdict, "file", bs->node_name);
153
sector based I/Os */
138
154
cluster_offset = bdrv_getlength(bs->file->bs);
139
/* Now get the QAPI type BlockdevCreateOptions */
155
- return bdrv_truncate(bs->file->bs, cluster_offset);
140
- qobj = qdict_crumple(qdict, errp);
156
+ return bdrv_truncate(bs->file, cluster_offset);
141
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
142
qobject_unref(qdict);
143
qdict = qobject_to(QDict, qobj);
144
if (qdict == NULL) {
145
diff --git a/block/qed.c b/block/qed.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/block/qed.c
148
+++ b/block/qed.c
149
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
150
qdict_put_str(qdict, "driver", "qed");
151
qdict_put_str(qdict, "file", bs->node_name);
152
153
- qobj = qdict_crumple(qdict, errp);
154
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
155
qobject_unref(qdict);
156
qdict = qobject_to(QDict, qobj);
157
if (qdict == NULL) {
158
diff --git a/block/rbd.c b/block/rbd.c
159
index XXXXXXX..XXXXXXX 100644
160
--- a/block/rbd.c
161
+++ b/block/rbd.c
162
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
157
}
163
}
158
164
159
buf = qemu_blockalign(bs, s->cluster_size);
165
/* Convert the remaining options into a QAPI object */
160
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
166
- crumpled = qdict_crumple(options, errp);
167
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
168
if (crumpled == NULL) {
169
r = -EINVAL;
170
goto out;
171
diff --git a/block/sheepdog.c b/block/sheepdog.c
172
index XXXXXXX..XXXXXXX 100644
173
--- a/block/sheepdog.c
174
+++ b/block/sheepdog.c
175
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
176
}
177
178
/* Get the QAPI object */
179
- crumpled = qdict_crumple(qdict, errp);
180
+ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
181
if (crumpled == NULL) {
182
ret = -EINVAL;
161
goto fail;
183
goto fail;
162
}
163
164
- ret = bdrv_truncate(bs->file->bs, (3 + l1_clusters) * s->cluster_size);
165
+ ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size);
166
if (ret < 0) {
167
goto fail;
168
}
169
diff --git a/block/raw-format.c b/block/raw-format.c
170
index XXXXXXX..XXXXXXX 100644
171
--- a/block/raw-format.c
172
+++ b/block/raw-format.c
173
@@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset)
174
175
s->size = offset;
176
offset += s->offset;
177
- return bdrv_truncate(bs->file->bs, offset);
178
+ return bdrv_truncate(bs->file, offset);
179
}
180
181
static int raw_media_changed(BlockDriverState *bs)
182
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/block/vhdx-log.c
185
+++ b/block/vhdx-log.c
186
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
187
if (new_file_size % (1024*1024)) {
188
/* round up to nearest 1MB boundary */
189
new_file_size = ((new_file_size >> 20) + 1) << 20;
190
- bdrv_truncate(bs->file->bs, new_file_size);
191
+ bdrv_truncate(bs->file, new_file_size);
192
}
193
}
194
qemu_vfree(desc_entries);
195
diff --git a/block/vhdx.c b/block/vhdx.c
184
diff --git a/block/vhdx.c b/block/vhdx.c
196
index XXXXXXX..XXXXXXX 100644
185
index XXXXXXX..XXXXXXX 100644
197
--- a/block/vhdx.c
186
--- a/block/vhdx.c
198
+++ b/block/vhdx.c
187
+++ b/block/vhdx.c
199
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
188
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
200
/* per the spec, the address for a block is in units of 1MB */
189
qdict_put_str(qdict, "driver", "vhdx");
201
*new_offset = ROUND_UP(*new_offset, 1024 * 1024);
190
qdict_put_str(qdict, "file", bs->node_name);
202
191
203
- return bdrv_truncate(bs->file->bs, *new_offset + s->block_size);
192
- qobj = qdict_crumple(qdict, errp);
204
+ return bdrv_truncate(bs->file, *new_offset + s->block_size);
193
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
194
qobject_unref(qdict);
195
qdict = qobject_to(QDict, qobj);
196
if (qdict == NULL) {
197
diff --git a/block/vpc.c b/block/vpc.c
198
index XXXXXXX..XXXXXXX 100644
199
--- a/block/vpc.c
200
+++ b/block/vpc.c
201
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
202
qdict_put_str(qdict, "driver", "vpc");
203
qdict_put_str(qdict, "file", bs->node_name);
204
205
- qobj = qdict_crumple(qdict, errp);
206
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
207
qobject_unref(qdict);
208
qdict = qobject_to(QDict, qobj);
209
if (qdict == NULL) {
210
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
211
index XXXXXXX..XXXXXXX 100644
212
--- a/qobject/block-qdict.c
213
+++ b/qobject/block-qdict.c
214
@@ -XXX,XX +XXX,XX @@
215
216
#include "qemu/osdep.h"
217
#include "block/qdict.h"
218
+#include "qapi/qmp/qbool.h"
219
#include "qapi/qmp/qlist.h"
220
+#include "qapi/qmp/qnum.h"
221
+#include "qapi/qmp/qstring.h"
222
#include "qemu/cutils.h"
223
#include "qapi/error.h"
224
225
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
205
}
226
}
206
227
207
/*
228
/**
208
diff --git a/include/block/block.h b/include/block/block.h
229
+ * qdict_crumple_for_keyval_qiv:
209
index XXXXXXX..XXXXXXX 100644
230
+ * @src: the flat dictionary (only scalar values) to crumple
210
--- a/include/block/block.h
231
+ * @errp: location to store error
211
+++ b/include/block/block.h
232
+ *
212
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
233
+ * Like qdict_crumple(), but additionally transforms scalar values so
213
const char *backing_file);
234
+ * the result can be passed to qobject_input_visitor_new_keyval().
214
int bdrv_get_backing_file_depth(BlockDriverState *bs);
235
+ *
215
void bdrv_refresh_filename(BlockDriverState *bs);
236
+ * The block subsystem uses this function to prepare its flat QDict
216
-int bdrv_truncate(BlockDriverState *bs, int64_t offset);
237
+ * with possibly confused scalar types for a visit. It should not be
217
+int bdrv_truncate(BdrvChild *child, int64_t offset);
238
+ * used for anything else, and it should go away once the block
218
int64_t bdrv_nb_sectors(BlockDriverState *bs);
239
+ * subsystem has been cleaned up.
219
int64_t bdrv_getlength(BlockDriverState *bs);
240
+ */
220
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
241
+QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp)
242
+{
243
+ QDict *tmp = NULL;
244
+ char *buf;
245
+ const char *s;
246
+ const QDictEntry *ent;
247
+ QObject *dst;
248
+
249
+ for (ent = qdict_first(src); ent; ent = qdict_next(src, ent)) {
250
+ buf = NULL;
251
+ switch (qobject_type(ent->value)) {
252
+ case QTYPE_QNULL:
253
+ case QTYPE_QSTRING:
254
+ continue;
255
+ case QTYPE_QNUM:
256
+ s = buf = qnum_to_string(qobject_to(QNum, ent->value));
257
+ break;
258
+ case QTYPE_QDICT:
259
+ case QTYPE_QLIST:
260
+ /* @src isn't flat; qdict_crumple() will fail */
261
+ continue;
262
+ case QTYPE_QBOOL:
263
+ s = qbool_get_bool(qobject_to(QBool, ent->value))
264
+ ? "on" : "off";
265
+ break;
266
+ default:
267
+ abort();
268
+ }
269
+
270
+ if (!tmp) {
271
+ tmp = qdict_clone_shallow(src);
272
+ }
273
+ qdict_put(tmp, ent->key, qstring_from_str(s));
274
+ g_free(buf);
275
+ }
276
+
277
+ dst = qdict_crumple(tmp ?: src, errp);
278
+ qobject_unref(tmp);
279
+ return dst;
280
+}
281
+
282
+/**
283
* qdict_array_entries(): Returns the number of direct array entries if the
284
* sub-QDict of src specified by the prefix in subqdict (or src itself for
285
* prefix == "") is valid as an array, i.e. the length of the created list if
221
--
286
--
222
1.8.3.1
287
2.13.6
223
288
224
289
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Markus Armbruster <armbru@redhat.com>
2
2
3
When using file system that does not support fallocate() (e.g. NFS <
3
The previous commit fixed -blockdev breakage due to misuse of the
4
4.2), truncating the file only when preallocation=OFF speeds up creating
4
qobject input visitor's keyval flavor in bdrv_file_open(). The commit
5
raw file.
5
message explain why using the plain flavor would be just as wrong; it
6
would break -drive. Turns out we break it in three places:
7
nbd_open(), sd_open() and ssh_file_open(). They are even marked
8
FIXME. Example breakage:
6
9
7
Here is example run, tested on Fedora 24 machine, creating raw file on
10
$ qemu-system-x86 -drive node-name=n1,driver=nbd,server.type=inet,server.host=localhost,server.port=1234,server.numeric=off
8
NFS version 3 server.
11
qemu-system-x86: -drive node-name=n1,driver=nbd,server.type=inet,server.host=localhost,server.port=1234,server.numeric=off: Invalid parameter type for 'numeric', expected: boolean
9
12
10
$ time ./qemu-img-master create -f raw -o preallocation=falloc mnt/test 1g
13
Fix it the same way: replace qdict_crumple() by
11
Formatting 'mnt/test', fmt=raw size=1073741824 preallocation=falloc
14
qdict_crumple_for_keyval_qiv(), and switch from plain to the keyval
15
flavor.
12
16
13
real    0m21.185s
17
Signed-off-by: Markus Armbruster <armbru@redhat.com>
14
user    0m0.022s
18
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
sys    0m0.574s
16
17
$ time ./qemu-img-fix create -f raw -o preallocation=falloc mnt/test 1g
18
Formatting 'mnt/test', fmt=raw size=1073741824 preallocation=falloc
19
20
real    0m11.601s
21
user    0m0.016s
22
sys    0m0.525s
23
24
$ time dd if=/dev/zero of=mnt/test bs=1M count=1024 oflag=direct
25
1024+0 records in
26
1024+0 records out
27
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 15.6627 s, 68.6 MB/s
28
29
real    0m16.104s
30
user    0m0.009s
31
sys    0m0.220s
32
33
Running with strace we can see that without this change we do one
34
pread() and one pwrite() for each block. With this change, we do only
35
one pwrite() per block.
36
37
$ strace ./qemu-img-master create -f raw -o preallocation=falloc mnt/test 8192
38
...
39
pread64(9, "\0", 1, 4095) = 1
40
pwrite64(9, "\0", 1, 4095) = 1
41
pread64(9, "\0", 1, 8191) = 1
42
pwrite64(9, "\0", 1, 8191) = 1
43
44
$ strace ./qemu-img-fix create -f raw -o preallocation=falloc mnt/test 8192
45
...
46
pwrite64(9, "\0", 1, 4095) = 1
47
pwrite64(9, "\0", 1, 8191) = 1
48
49
This happens because posix_fallocate is checking if each block is
50
allocated before writing a byte to the block, and when truncating the
51
file before preallocation, all blocks are unallocated.
52
53
Signed-off-by: Nir Soffer <nirsof@gmail.com>
54
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
55
---
20
---
56
block/file-posix.c | 11 ++++-------
21
block/nbd.c | 12 ++----------
57
1 file changed, 4 insertions(+), 7 deletions(-)
22
block/sheepdog.c | 12 ++----------
23
block/ssh.c | 12 ++----------
24
3 files changed, 6 insertions(+), 30 deletions(-)
58
25
59
diff --git a/block/file-posix.c b/block/file-posix.c
26
diff --git a/block/nbd.c b/block/nbd.c
60
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
61
--- a/block/file-posix.c
28
--- a/block/nbd.c
62
+++ b/block/file-posix.c
29
+++ b/block/nbd.c
63
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
30
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
64
#endif
31
goto done;
65
}
32
}
66
33
67
- if (ftruncate(fd, total_size) != 0) {
34
- crumpled_addr = qdict_crumple(addr, errp);
68
- result = -errno;
35
+ crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp);
69
- error_setg_errno(errp, -result, "Could not resize file");
36
if (!crumpled_addr) {
70
- goto out_close;
37
goto done;
71
- }
72
-
73
switch (prealloc) {
74
#ifdef CONFIG_POSIX_FALLOCATE
75
case PREALLOC_MODE_FALLOC:
76
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
77
break;
78
}
38
}
79
case PREALLOC_MODE_OFF:
39
80
+ if (ftruncate(fd, total_size) != 0) {
40
- /*
81
+ result = -errno;
41
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
82
+ error_setg_errno(errp, -result, "Could not resize file");
42
- * server.type=inet. .to doesn't matter, it's ignored anyway.
83
+ }
43
- * That's because when @options come from -blockdev or
84
break;
44
- * blockdev_add, members are typed according to the QAPI schema,
85
default:
45
- * but when they come from -drive, they're all QString. The
86
result = -EINVAL;
46
- * visitor expects the former.
87
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
47
- */
88
break;
48
- iv = qobject_input_visitor_new(crumpled_addr);
49
+ iv = qobject_input_visitor_new_keyval(crumpled_addr);
50
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
51
if (local_err) {
52
error_propagate(errp, local_err);
53
diff --git a/block/sheepdog.c b/block/sheepdog.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/sheepdog.c
56
+++ b/block/sheepdog.c
57
@@ -XXX,XX +XXX,XX @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
58
59
qdict_extract_subqdict(options, &server, "server.");
60
61
- crumpled_server = qdict_crumple(server, errp);
62
+ crumpled_server = qdict_crumple_for_keyval_qiv(server, errp);
63
if (!crumpled_server) {
64
goto done;
89
}
65
}
90
66
91
-out_close:
67
- /*
92
if (qemu_close(fd) != 0 && result == 0) {
68
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
93
result = -errno;
69
- * server.type=inet. .to doesn't matter, it's ignored anyway.
94
error_setg_errno(errp, -result, "Could not close the new file");
70
- * That's because when @options come from -blockdev or
71
- * blockdev_add, members are typed according to the QAPI schema,
72
- * but when they come from -drive, they're all QString. The
73
- * visitor expects the former.
74
- */
75
- iv = qobject_input_visitor_new(crumpled_server);
76
+ iv = qobject_input_visitor_new_keyval(crumpled_server);
77
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
78
if (local_err) {
79
error_propagate(errp, local_err);
80
diff --git a/block/ssh.c b/block/ssh.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/block/ssh.c
83
+++ b/block/ssh.c
84
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
85
}
86
87
/* Create the QAPI object */
88
- crumpled = qdict_crumple(options, errp);
89
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
90
if (crumpled == NULL) {
91
goto fail;
92
}
93
94
- /*
95
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive.
96
- * .to doesn't matter, it's ignored anyway.
97
- * That's because when @options come from -blockdev or
98
- * blockdev_add, members are typed according to the QAPI schema,
99
- * but when they come from -drive, they're all QString. The
100
- * visitor expects the former.
101
- */
102
- v = qobject_input_visitor_new(crumpled);
103
+ v = qobject_input_visitor_new_keyval(crumpled);
104
visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err);
105
visit_free(v);
106
qobject_unref(crumpled);
95
--
107
--
96
1.8.3.1
108
2.13.6
97
109
98
110
diff view generated by jsdifflib
1
In order to able to convert bdrv_truncate() to take a BdrvChild and
1
From: Markus Armbruster <armbru@redhat.com>
2
later to correctly check the resize permission here, we need to use a
2
3
BlockBackend for resizing the image.
3
The following pattern occurs in the .bdrv_co_create_opts() methods of
4
4
parallels, qcow, qcow2, qed, vhdx and vpc:
5
6
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
7
qobject_unref(qdict);
8
qdict = qobject_to(QDict, qobj);
9
if (qdict == NULL) {
10
ret = -EINVAL;
11
goto done;
12
}
13
14
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
15
[...]
16
ret = 0;
17
done:
18
qobject_unref(qdict);
19
[...]
20
return ret;
21
22
If qobject_to() fails, we return failure without setting errp. That's
23
wrong. As far as I can tell, it cannot fail here. Clean it up
24
anyway, by removing the useless conversion.
25
26
Signed-off-by: Markus Armbruster <armbru@redhat.com>
27
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
29
---
8
block/qcow2.c | 6 +++++-
30
block/parallels.c | 9 ++++-----
9
1 file changed, 5 insertions(+), 1 deletion(-)
31
block/qcow.c | 9 ++++-----
10
32
block/qcow2.c | 9 ++++-----
33
block/qed.c | 9 ++++-----
34
block/vhdx.c | 9 ++++-----
35
block/vpc.c | 9 ++++-----
36
6 files changed, 24 insertions(+), 30 deletions(-)
37
38
diff --git a/block/parallels.c b/block/parallels.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block/parallels.c
41
+++ b/block/parallels.c
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
43
BlockdevCreateOptions *create_options = NULL;
44
Error *local_err = NULL;
45
BlockDriverState *bs = NULL;
46
- QDict *qdict = NULL;
47
+ QDict *qdict;
48
QObject *qobj;
49
Visitor *v;
50
int ret;
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
52
qdict_put_str(qdict, "file", bs->node_name);
53
54
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
55
- qobject_unref(qdict);
56
- qdict = qobject_to(QDict, qobj);
57
- if (qdict == NULL) {
58
+ if (!qobj) {
59
ret = -EINVAL;
60
goto done;
61
}
62
63
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
64
+ v = qobject_input_visitor_new_keyval(qobj);
65
+ qobject_unref(qobj);
66
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
67
visit_free(v);
68
69
diff --git a/block/qcow.c b/block/qcow.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/qcow.c
72
+++ b/block/qcow.c
73
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
74
{
75
BlockdevCreateOptions *create_options = NULL;
76
BlockDriverState *bs = NULL;
77
- QDict *qdict = NULL;
78
+ QDict *qdict;
79
QObject *qobj;
80
Visitor *v;
81
const char *val;
82
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
83
qdict_put_str(qdict, "file", bs->node_name);
84
85
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
86
- qobject_unref(qdict);
87
- qdict = qobject_to(QDict, qobj);
88
- if (qdict == NULL) {
89
+ if (!qobj) {
90
ret = -EINVAL;
91
goto fail;
92
}
93
94
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
95
+ v = qobject_input_visitor_new_keyval(qobj);
96
+ qobject_unref(qobj);
97
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
98
visit_free(v);
99
11
diff --git a/block/qcow2.c b/block/qcow2.c
100
diff --git a/block/qcow2.c b/block/qcow2.c
12
index XXXXXXX..XXXXXXX 100644
101
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qcow2.c
102
--- a/block/qcow2.c
14
+++ b/block/qcow2.c
103
+++ b/block/qcow2.c
15
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
104
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
16
}
105
Error **errp)
17
106
{
18
if (new_size) {
107
BlockdevCreateOptions *create_options = NULL;
19
- ret = bdrv_truncate(bs, new_size);
108
- QDict *qdict = NULL;
20
+ BlockBackend *blk = blk_new();
109
+ QDict *qdict;
21
+ blk_insert_bs(blk, bs);
110
QObject *qobj;
22
+ ret = blk_truncate(blk, new_size);
111
Visitor *v;
23
+ blk_unref(blk);
112
BlockDriverState *bs = NULL;
24
+
113
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
25
if (ret < 0) {
114
26
return ret;
115
/* Now get the QAPI type BlockdevCreateOptions */
27
}
116
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
117
- qobject_unref(qdict);
118
- qdict = qobject_to(QDict, qobj);
119
- if (qdict == NULL) {
120
+ if (!qobj) {
121
ret = -EINVAL;
122
goto finish;
123
}
124
125
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
126
+ v = qobject_input_visitor_new_keyval(qobj);
127
+ qobject_unref(qobj);
128
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
129
visit_free(v);
130
131
diff --git a/block/qed.c b/block/qed.c
132
index XXXXXXX..XXXXXXX 100644
133
--- a/block/qed.c
134
+++ b/block/qed.c
135
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
136
Error **errp)
137
{
138
BlockdevCreateOptions *create_options = NULL;
139
- QDict *qdict = NULL;
140
+ QDict *qdict;
141
QObject *qobj;
142
Visitor *v;
143
BlockDriverState *bs = NULL;
144
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
145
qdict_put_str(qdict, "file", bs->node_name);
146
147
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
148
- qobject_unref(qdict);
149
- qdict = qobject_to(QDict, qobj);
150
- if (qdict == NULL) {
151
+ if (!qobj) {
152
ret = -EINVAL;
153
goto fail;
154
}
155
156
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
157
+ v = qobject_input_visitor_new_keyval(qobj);
158
+ qobject_unref(qobj);
159
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
160
visit_free(v);
161
162
diff --git a/block/vhdx.c b/block/vhdx.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/block/vhdx.c
165
+++ b/block/vhdx.c
166
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
167
Error **errp)
168
{
169
BlockdevCreateOptions *create_options = NULL;
170
- QDict *qdict = NULL;
171
+ QDict *qdict;
172
QObject *qobj;
173
Visitor *v;
174
BlockDriverState *bs = NULL;
175
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
176
qdict_put_str(qdict, "file", bs->node_name);
177
178
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
179
- qobject_unref(qdict);
180
- qdict = qobject_to(QDict, qobj);
181
- if (qdict == NULL) {
182
+ if (!qobj) {
183
ret = -EINVAL;
184
goto fail;
185
}
186
187
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
188
+ v = qobject_input_visitor_new_keyval(qobj);
189
+ qobject_unref(qobj);
190
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
191
visit_free(v);
192
193
diff --git a/block/vpc.c b/block/vpc.c
194
index XXXXXXX..XXXXXXX 100644
195
--- a/block/vpc.c
196
+++ b/block/vpc.c
197
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
198
QemuOpts *opts, Error **errp)
199
{
200
BlockdevCreateOptions *create_options = NULL;
201
- QDict *qdict = NULL;
202
+ QDict *qdict;
203
QObject *qobj;
204
Visitor *v;
205
BlockDriverState *bs = NULL;
206
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
207
qdict_put_str(qdict, "file", bs->node_name);
208
209
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
210
- qobject_unref(qdict);
211
- qdict = qobject_to(QDict, qobj);
212
- if (qdict == NULL) {
213
+ if (!qobj) {
214
ret = -EINVAL;
215
goto fail;
216
}
217
218
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
219
+ v = qobject_input_visitor_new_keyval(qobj);
220
+ qobject_unref(qobj);
221
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
222
visit_free(v);
223
28
--
224
--
29
1.8.3.1
225
2.13.6
30
226
31
227
diff view generated by jsdifflib
1
This is the part of bdrv_open_child() that opens a BDS with option
1
From: Markus Armbruster <armbru@redhat.com>
2
inheritance, but doesn't attach it as a child to the parent yet.
3
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
6
---
7
block.c | 61 +++++++++++++++++++++++++++++++++++++------------------------
7
include/block/qdict.h | 3 ++-
8
1 file changed, 37 insertions(+), 24 deletions(-)
8
block/nbd.c | 7 ++-----
9
block/nfs.c | 7 ++-----
10
block/parallels.c | 7 ++-----
11
block/qcow.c | 7 ++-----
12
block/qcow2.c | 7 ++-----
13
block/qed.c | 7 ++-----
14
block/rbd.c | 7 ++-----
15
block/sheepdog.c | 14 ++++----------
16
block/ssh.c | 7 ++-----
17
block/vhdx.c | 7 ++-----
18
block/vpc.c | 7 ++-----
19
qobject/block-qdict.c | 28 +++++++++++++++++++++++++++-
20
13 files changed, 53 insertions(+), 62 deletions(-)
9
21
10
diff --git a/block.c b/block.c
22
diff --git a/include/block/qdict.h b/include/block/qdict.h
11
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
12
--- a/block.c
24
--- a/include/block/qdict.h
13
+++ b/block.c
25
+++ b/include/block/qdict.h
14
@@ -XXX,XX +XXX,XX @@ free_exit:
26
@@ -XXX,XX +XXX,XX @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
15
return ret;
27
void qdict_array_split(QDict *src, QList **dst);
28
int qdict_array_entries(QDict *src, const char *subqdict);
29
QObject *qdict_crumple(const QDict *src, Error **errp);
30
-QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp);
31
void qdict_flatten(QDict *qdict);
32
33
typedef struct QDictRenames {
34
@@ -XXX,XX +XXX,XX @@ typedef struct QDictRenames {
35
} QDictRenames;
36
bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
37
38
+Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict,
39
+ Error **errp);
40
#endif
41
diff --git a/block/nbd.c b/block/nbd.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block/nbd.c
44
+++ b/block/nbd.c
45
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
46
{
47
SocketAddress *saddr = NULL;
48
QDict *addr = NULL;
49
- QObject *crumpled_addr = NULL;
50
Visitor *iv = NULL;
51
Error *local_err = NULL;
52
53
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
54
goto done;
55
}
56
57
- crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp);
58
- if (!crumpled_addr) {
59
+ iv = qobject_input_visitor_new_flat_confused(addr, errp);
60
+ if (!iv) {
61
goto done;
62
}
63
64
- iv = qobject_input_visitor_new_keyval(crumpled_addr);
65
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
66
if (local_err) {
67
error_propagate(errp, local_err);
68
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
69
70
done:
71
qobject_unref(addr);
72
- qobject_unref(crumpled_addr);
73
visit_free(iv);
74
return saddr;
16
}
75
}
17
76
diff --git a/block/nfs.c b/block/nfs.c
18
-/*
77
index XXXXXXX..XXXXXXX 100644
19
- * Opens a disk image whose options are given as BlockdevRef in another block
78
--- a/block/nfs.c
20
- * device's options.
79
+++ b/block/nfs.c
21
- *
80
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
22
- * If allow_none is true, no image will be opened if filename is false and no
81
Error **errp)
23
- * BlockdevRef is given. NULL will be returned, but errp remains unset.
82
{
24
- *
83
BlockdevOptionsNfs *opts = NULL;
25
- * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
84
- QObject *crumpled = NULL;
26
- * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
85
Visitor *v;
27
- * itself, all options starting with "${bdref_key}." are considered part of the
86
const QDictEntry *e;
28
- * BlockdevRef.
87
Error *local_err = NULL;
29
- *
88
30
- * The BlockdevRef will be removed from the options QDict.
89
- crumpled = qdict_crumple_for_keyval_qiv(options, errp);
31
- */
90
- if (crumpled == NULL) {
32
-BdrvChild *bdrv_open_child(const char *filename,
91
+ v = qobject_input_visitor_new_flat_confused(options, errp);
33
- QDict *options, const char *bdref_key,
92
+ if (!v) {
34
- BlockDriverState* parent,
93
return NULL;
35
- const BdrvChildRole *child_role,
94
}
36
- bool allow_none, Error **errp)
95
37
+static BlockDriverState *
96
- v = qobject_input_visitor_new_keyval(crumpled);
38
+bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
97
visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
39
+ BlockDriverState *parent, const BdrvChildRole *child_role,
98
visit_free(v);
40
+ bool allow_none, Error **errp)
99
- qobject_unref(crumpled);
41
{
100
42
- BdrvChild *c = NULL;
101
if (local_err) {
43
- BlockDriverState *bs;
102
error_propagate(errp, local_err);
44
+ BlockDriverState *bs = NULL;
103
diff --git a/block/parallels.c b/block/parallels.c
45
QDict *image_options;
104
index XXXXXXX..XXXXXXX 100644
46
char *bdref_key_dot;
105
--- a/block/parallels.c
47
const char *reference;
106
+++ b/block/parallels.c
48
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
107
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
108
Error *local_err = NULL;
109
BlockDriverState *bs = NULL;
110
QDict *qdict;
111
- QObject *qobj;
112
Visitor *v;
113
int ret;
114
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
116
qdict_put_str(qdict, "driver", "parallels");
117
qdict_put_str(qdict, "file", bs->node_name);
118
119
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
120
- if (!qobj) {
121
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
122
+ if (!v) {
123
ret = -EINVAL;
49
goto done;
124
goto done;
50
}
125
}
51
126
52
- c = bdrv_attach_child(parent, bs, bdref_key, child_role);
127
- v = qobject_input_visitor_new_keyval(qobj);
53
-
128
- qobject_unref(qobj);
129
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
130
visit_free(v);
131
132
diff --git a/block/qcow.c b/block/qcow.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/block/qcow.c
135
+++ b/block/qcow.c
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
137
BlockdevCreateOptions *create_options = NULL;
138
BlockDriverState *bs = NULL;
139
QDict *qdict;
140
- QObject *qobj;
141
Visitor *v;
142
const char *val;
143
Error *local_err = NULL;
144
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
145
qdict_put_str(qdict, "driver", "qcow");
146
qdict_put_str(qdict, "file", bs->node_name);
147
148
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
149
- if (!qobj) {
150
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
151
+ if (!v) {
152
ret = -EINVAL;
153
goto fail;
154
}
155
156
- v = qobject_input_visitor_new_keyval(qobj);
157
- qobject_unref(qobj);
158
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
159
visit_free(v);
160
161
diff --git a/block/qcow2.c b/block/qcow2.c
162
index XXXXXXX..XXXXXXX 100644
163
--- a/block/qcow2.c
164
+++ b/block/qcow2.c
165
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
166
{
167
BlockdevCreateOptions *create_options = NULL;
168
QDict *qdict;
169
- QObject *qobj;
170
Visitor *v;
171
BlockDriverState *bs = NULL;
172
Error *local_err = NULL;
173
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
174
qdict_put_str(qdict, "file", bs->node_name);
175
176
/* Now get the QAPI type BlockdevCreateOptions */
177
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
178
- if (!qobj) {
179
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
180
+ if (!v) {
181
ret = -EINVAL;
182
goto finish;
183
}
184
185
- v = qobject_input_visitor_new_keyval(qobj);
186
- qobject_unref(qobj);
187
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
188
visit_free(v);
189
190
diff --git a/block/qed.c b/block/qed.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/block/qed.c
193
+++ b/block/qed.c
194
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
195
{
196
BlockdevCreateOptions *create_options = NULL;
197
QDict *qdict;
198
- QObject *qobj;
199
Visitor *v;
200
BlockDriverState *bs = NULL;
201
Error *local_err = NULL;
202
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
203
qdict_put_str(qdict, "driver", "qed");
204
qdict_put_str(qdict, "file", bs->node_name);
205
206
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
207
- if (!qobj) {
208
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
209
+ if (!v) {
210
ret = -EINVAL;
211
goto fail;
212
}
213
214
- v = qobject_input_visitor_new_keyval(qobj);
215
- qobject_unref(qobj);
216
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
217
visit_free(v);
218
219
diff --git a/block/rbd.c b/block/rbd.c
220
index XXXXXXX..XXXXXXX 100644
221
--- a/block/rbd.c
222
+++ b/block/rbd.c
223
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
224
BDRVRBDState *s = bs->opaque;
225
BlockdevOptionsRbd *opts = NULL;
226
Visitor *v;
227
- QObject *crumpled = NULL;
228
const QDictEntry *e;
229
Error *local_err = NULL;
230
char *keypairs, *secretid;
231
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
232
}
233
234
/* Convert the remaining options into a QAPI object */
235
- crumpled = qdict_crumple_for_keyval_qiv(options, errp);
236
- if (crumpled == NULL) {
237
+ v = qobject_input_visitor_new_flat_confused(options, errp);
238
+ if (!v) {
239
r = -EINVAL;
240
goto out;
241
}
242
243
- v = qobject_input_visitor_new_keyval(crumpled);
244
visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err);
245
visit_free(v);
246
- qobject_unref(crumpled);
247
248
if (local_err) {
249
error_propagate(errp, local_err);
250
diff --git a/block/sheepdog.c b/block/sheepdog.c
251
index XXXXXXX..XXXXXXX 100644
252
--- a/block/sheepdog.c
253
+++ b/block/sheepdog.c
254
@@ -XXX,XX +XXX,XX @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
255
static SocketAddress *sd_server_config(QDict *options, Error **errp)
256
{
257
QDict *server = NULL;
258
- QObject *crumpled_server = NULL;
259
Visitor *iv = NULL;
260
SocketAddress *saddr = NULL;
261
Error *local_err = NULL;
262
263
qdict_extract_subqdict(options, &server, "server.");
264
265
- crumpled_server = qdict_crumple_for_keyval_qiv(server, errp);
266
- if (!crumpled_server) {
267
+ iv = qobject_input_visitor_new_flat_confused(server, errp);
268
+ if (!iv) {
269
goto done;
270
}
271
272
- iv = qobject_input_visitor_new_keyval(crumpled_server);
273
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
274
if (local_err) {
275
error_propagate(errp, local_err);
276
@@ -XXX,XX +XXX,XX @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
277
54
done:
278
done:
55
qdict_del(options, bdref_key);
279
visit_free(iv);
56
- return c;
280
- qobject_unref(crumpled_server);
57
+ return bs;
281
qobject_unref(server);
58
+}
282
return saddr;
283
}
284
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
285
{
286
BlockdevCreateOptions *create_options = NULL;
287
QDict *qdict, *location_qdict;
288
- QObject *crumpled;
289
Visitor *v;
290
char *redundancy;
291
Error *local_err = NULL;
292
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
293
}
294
295
/* Get the QAPI object */
296
- crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
297
- if (crumpled == NULL) {
298
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
299
+ if (!v) {
300
ret = -EINVAL;
301
goto fail;
302
}
303
304
- v = qobject_input_visitor_new_keyval(crumpled);
305
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
306
visit_free(v);
307
- qobject_unref(crumpled);
308
309
if (local_err) {
310
error_propagate(errp, local_err);
311
diff --git a/block/ssh.c b/block/ssh.c
312
index XXXXXXX..XXXXXXX 100644
313
--- a/block/ssh.c
314
+++ b/block/ssh.c
315
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
316
BlockdevOptionsSsh *result = NULL;
317
QemuOpts *opts = NULL;
318
Error *local_err = NULL;
319
- QObject *crumpled;
320
const QDictEntry *e;
321
Visitor *v;
322
323
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
324
}
325
326
/* Create the QAPI object */
327
- crumpled = qdict_crumple_for_keyval_qiv(options, errp);
328
- if (crumpled == NULL) {
329
+ v = qobject_input_visitor_new_flat_confused(options, errp);
330
+ if (!v) {
331
goto fail;
332
}
333
334
- v = qobject_input_visitor_new_keyval(crumpled);
335
visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err);
336
visit_free(v);
337
- qobject_unref(crumpled);
338
339
if (local_err) {
340
error_propagate(errp, local_err);
341
diff --git a/block/vhdx.c b/block/vhdx.c
342
index XXXXXXX..XXXXXXX 100644
343
--- a/block/vhdx.c
344
+++ b/block/vhdx.c
345
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
346
{
347
BlockdevCreateOptions *create_options = NULL;
348
QDict *qdict;
349
- QObject *qobj;
350
Visitor *v;
351
BlockDriverState *bs = NULL;
352
Error *local_err = NULL;
353
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
354
qdict_put_str(qdict, "driver", "vhdx");
355
qdict_put_str(qdict, "file", bs->node_name);
356
357
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
358
- if (!qobj) {
359
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
360
+ if (!v) {
361
ret = -EINVAL;
362
goto fail;
363
}
364
365
- v = qobject_input_visitor_new_keyval(qobj);
366
- qobject_unref(qobj);
367
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
368
visit_free(v);
369
370
diff --git a/block/vpc.c b/block/vpc.c
371
index XXXXXXX..XXXXXXX 100644
372
--- a/block/vpc.c
373
+++ b/block/vpc.c
374
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
375
{
376
BlockdevCreateOptions *create_options = NULL;
377
QDict *qdict;
378
- QObject *qobj;
379
Visitor *v;
380
BlockDriverState *bs = NULL;
381
Error *local_err = NULL;
382
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
383
qdict_put_str(qdict, "driver", "vpc");
384
qdict_put_str(qdict, "file", bs->node_name);
385
386
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
387
- if (!qobj) {
388
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
389
+ if (!v) {
390
ret = -EINVAL;
391
goto fail;
392
}
393
394
- v = qobject_input_visitor_new_keyval(qobj);
395
- qobject_unref(qobj);
396
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
397
visit_free(v);
398
399
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
400
index XXXXXXX..XXXXXXX 100644
401
--- a/qobject/block-qdict.c
402
+++ b/qobject/block-qdict.c
403
@@ -XXX,XX +XXX,XX @@
404
#include "qapi/qmp/qlist.h"
405
#include "qapi/qmp/qnum.h"
406
#include "qapi/qmp/qstring.h"
407
+#include "qapi/qobject-input-visitor.h"
408
#include "qemu/cutils.h"
409
#include "qapi/error.h"
410
411
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
412
* used for anything else, and it should go away once the block
413
* subsystem has been cleaned up.
414
*/
415
-QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp)
416
+static QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp)
417
{
418
QDict *tmp = NULL;
419
char *buf;
420
@@ -XXX,XX +XXX,XX @@ bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
421
}
422
return true;
423
}
59
+
424
+
60
+/*
425
+/*
61
+ * Opens a disk image whose options are given as BlockdevRef in another block
426
+ * Create a QObject input visitor for flat @qdict with possibly
62
+ * device's options.
427
+ * confused scalar types.
63
+ *
428
+ *
64
+ * If allow_none is true, no image will be opened if filename is false and no
429
+ * The block subsystem uses this function to visit its flat QDict with
65
+ * BlockdevRef is given. NULL will be returned, but errp remains unset.
430
+ * possibly confused scalar types. It should not be used for anything
66
+ *
431
+ * else, and it should go away once the block subsystem has been
67
+ * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
432
+ * cleaned up.
68
+ * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
69
+ * itself, all options starting with "${bdref_key}." are considered part of the
70
+ * BlockdevRef.
71
+ *
72
+ * The BlockdevRef will be removed from the options QDict.
73
+ */
433
+ */
74
+BdrvChild *bdrv_open_child(const char *filename,
434
+Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict,
75
+ QDict *options, const char *bdref_key,
435
+ Error **errp)
76
+ BlockDriverState *parent,
77
+ const BdrvChildRole *child_role,
78
+ bool allow_none, Error **errp)
79
+{
436
+{
80
+ BlockDriverState *bs;
437
+ QObject *crumpled;
438
+ Visitor *v;
81
+
439
+
82
+ bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_role,
440
+ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
83
+ allow_none, errp);
441
+ if (!crumpled) {
84
+ if (bs == NULL) {
85
+ return NULL;
442
+ return NULL;
86
+ }
443
+ }
87
+
444
+
88
+ return bdrv_attach_child(parent, bs, bdref_key, child_role);
445
+ v = qobject_input_visitor_new_keyval(crumpled);
89
}
446
+ qobject_unref(crumpled);
90
447
+ return v;
91
static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
448
+}
92
--
449
--
93
1.8.3.1
450
2.13.6
94
451
95
452
diff view generated by jsdifflib
1
We should not try to assign a not yet opened node as the backing file,
1
From: Markus Armbruster <armbru@redhat.com>
2
because as soon as the permission system is added it will fail. The
3
just added bdrv_new_open_driver() function is the right tool to open a
4
file with an internal driver, use it.
5
2
6
In case anyone wonders whether that magic fake backing file to trigger a
3
Remaining uses of qobject_input_visitor_new_keyval() in the block
7
special action on 'commit' actually works today: No, not for me. One
4
subsystem:
8
reason is that we've been adding a raw format driver on top for several
9
years now and raw doesn't support commit. Other reasons include that the
10
backing file isn't writable and the driver doesn't support reopen, and
11
it's also size 0 and the driver doesn't support bdrv_truncate. All of
12
these are easily fixable, but then 'commit' ended up in an infinite loop
13
deep in the vvfat code for me, so I thought I'd best leave it alone. I'm
14
not really sure what it was supposed to do anyway.
15
5
6
* block_crypto_open_opts_init()
7
Currently doesn't visit any non-string scalars, thus safe. It's
8
called from
9
- block_crypto_open_luks()
10
Creates the QDict with qemu_opts_to_qdict_filtered(), which
11
creates only string scalars, but has a TODO asking for other types.
12
- qcow_open()
13
- qcow2_open(), qcow2_co_invalidate_cache(), qcow2_reopen_prepare()
14
15
* block_crypto_create_opts_init(), called from
16
- block_crypto_co_create_opts_luks()
17
Also creates the QDict with qemu_opts_to_qdict_filtered().
18
19
* vdi_co_create_opts()
20
Also creates the QDict with qemu_opts_to_qdict_filtered().
21
22
Replace these uses by qobject_input_visitor_new_flat_confused() for
23
robustness. This adds crumpling. Right now, that's a no-op, but if
24
we ever extend these things in non-flat ways, crumpling will be
25
needed.
26
27
Signed-off-by: Markus Armbruster <armbru@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
---
29
---
19
block/vvfat.c | 10 +++++-----
30
block/crypto.c | 12 +++++++++---
20
1 file changed, 5 insertions(+), 5 deletions(-)
31
block/vdi.c | 8 ++++++--
32
2 files changed, 15 insertions(+), 5 deletions(-)
21
33
22
diff --git a/block/vvfat.c b/block/vvfat.c
34
diff --git a/block/crypto.c b/block/crypto.c
23
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
24
--- a/block/vvfat.c
36
--- a/block/crypto.c
25
+++ b/block/vvfat.c
37
+++ b/block/crypto.c
26
@@ -XXX,XX +XXX,XX @@ static void write_target_close(BlockDriverState *bs) {
38
@@ -XXX,XX +XXX,XX @@
27
39
#include "qemu/osdep.h"
28
static BlockDriver vvfat_write_target = {
40
29
.format_name = "vvfat_write_target",
41
#include "block/block_int.h"
30
+ .instance_size = sizeof(void*),
42
+#include "block/qdict.h"
31
.bdrv_co_pwritev = write_target_commit,
43
#include "sysemu/block-backend.h"
32
.bdrv_close = write_target_close,
44
#include "crypto/block.h"
33
};
45
#include "qapi/opts-visitor.h"
34
@@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
46
#include "qapi/qapi-visit-crypto.h"
35
unlink(s->qcow_filename);
47
-#include "qapi/qmp/qdict.h"
36
#endif
48
#include "qapi/qobject-input-visitor.h"
37
49
#include "qapi/error.h"
38
- backing = bdrv_new();
50
#include "qemu/option.h"
39
+ backing = bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALLOW_RDWR,
51
@@ -XXX,XX +XXX,XX @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
40
+ &error_abort);
52
ret = g_new0(QCryptoBlockOpenOptions, 1);
41
+ *(void**) backing->opaque = s;
53
ret->format = format;
42
+
54
43
bdrv_set_backing_hd(s->bs, backing);
55
- v = qobject_input_visitor_new_keyval(QOBJECT(opts));
44
bdrv_unref(backing);
56
+ v = qobject_input_visitor_new_flat_confused(opts, &local_err);
45
57
+ if (local_err) {
46
- s->bs->backing->bs->drv = &vvfat_write_target;
58
+ goto out;
47
- s->bs->backing->bs->opaque = g_new(void *, 1);
59
+ }
48
- *(void**)s->bs->backing->bs->opaque = s;
60
49
-
61
visit_start_struct(v, NULL, NULL, 0, &local_err);
50
return 0;
62
if (local_err) {
51
63
@@ -XXX,XX +XXX,XX @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
52
err:
64
ret = g_new0(QCryptoBlockCreateOptions, 1);
65
ret->format = format;
66
67
- v = qobject_input_visitor_new_keyval(QOBJECT(opts));
68
+ v = qobject_input_visitor_new_flat_confused(opts, &local_err);
69
+ if (local_err) {
70
+ goto out;
71
+ }
72
73
visit_start_struct(v, NULL, NULL, 0, &local_err);
74
if (local_err) {
75
diff --git a/block/vdi.c b/block/vdi.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/vdi.c
78
+++ b/block/vdi.c
79
@@ -XXX,XX +XXX,XX @@
80
81
#include "qemu/osdep.h"
82
#include "qapi/error.h"
83
-#include "qapi/qmp/qdict.h"
84
#include "qapi/qobject-input-visitor.h"
85
#include "qapi/qapi-visit-block-core.h"
86
#include "block/block_int.h"
87
+#include "block/qdict.h"
88
#include "sysemu/block-backend.h"
89
#include "qemu/module.h"
90
#include "qemu/option.h"
91
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
92
}
93
94
/* Get the QAPI object */
95
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
96
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
97
+ if (!v) {
98
+ ret = -EINVAL;
99
+ goto done;
100
+ }
101
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
102
visit_free(v);
103
53
--
104
--
54
1.8.3.1
105
2.13.6
55
106
56
107
diff view generated by jsdifflib
1
From: Jeff Cody <jcody@redhat.com>
1
From: Markus Armbruster <armbru@redhat.com>
2
2
3
Some iotests (e.g. 174) try to filter the output of _make_test_image by
3
There's no need to restart the loop. We don't elsewhere, e.g. in
4
piping the stdout. Pipe the server stdout to /dev/null, so that filter
4
qdict_extract_subqdict(), qdict_join() and qemu_opts_absorb_qdict().
5
pipe does not need to wait until process completion.
5
Simplify accordingly.
6
6
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
7
Signed-off-by: Markus Armbruster <armbru@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
10
---
11
tests/qemu-iotests/common.rc | 2 +-
11
qobject/block-qdict.c | 18 +++---------------
12
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 3 insertions(+), 15 deletions(-)
13
13
14
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
14
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/common.rc
16
--- a/qobject/block-qdict.c
17
+++ b/tests/qemu-iotests/common.rc
17
+++ b/qobject/block-qdict.c
18
@@ -XXX,XX +XXX,XX @@ _make_test_img()
18
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
19
19
QObject *value;
20
# Start an NBD server on the image file, which is what we'll be talking to
20
const QDictEntry *entry, *next;
21
if [ $IMGPROTO = "nbd" ]; then
21
char *new_key;
22
- eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE &"
22
- bool delete;
23
+ eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE >/dev/null &"
23
24
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
24
entry = qdict_first(qdict);
25
fi
25
26
while (entry != NULL) {
27
-
28
next = qdict_next(qdict, entry);
29
value = qdict_entry_value(entry);
30
new_key = NULL;
31
- delete = false;
32
33
if (prefix) {
34
new_key = g_strdup_printf("%s.%s", prefix, entry->key);
35
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
36
* itself disappears. */
37
qdict_flatten_qdict(qobject_to(QDict, value), target,
38
new_key ? new_key : entry->key);
39
- delete = true;
40
+ qdict_del(qdict, entry->key);
41
} else if (qobject_type(value) == QTYPE_QLIST) {
42
qdict_flatten_qlist(qobject_to(QList, value), target,
43
new_key ? new_key : entry->key);
44
- delete = true;
45
+ qdict_del(qdict, entry->key);
46
} else if (prefix) {
47
/* All other objects are moved to the target unchanged. */
48
qdict_put_obj(target, new_key, qobject_ref(value));
49
- delete = true;
50
- }
51
-
52
- g_free(new_key);
53
-
54
- if (delete) {
55
qdict_del(qdict, entry->key);
56
-
57
- /* Restart loop after modifying the iterated QDict */
58
- entry = qdict_first(qdict);
59
- continue;
60
}
61
62
+ g_free(new_key);
63
entry = next;
64
}
26
}
65
}
27
--
66
--
28
1.8.3.1
67
2.13.6
29
68
30
69
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Markus Armbruster <armbru@redhat.com>
2
2
3
Now that we are truncating the file in both PREALLOC_MODE_FULL and
3
qdict_flatten_qdict() skips copying scalars from @qdict to @target
4
PREALLOC_MODE_OFF, not truncating in PREALLOC_MODE_FALLOC looks odd.
4
when the two are the same. Fair enough, but it uses a non-obvious
5
Add a comment explaining why we do not truncate in this case.
5
test for "same". Replace it by the obvious one. While there, improve
6
comments.
6
7
7
Signed-off-by: Nir Soffer <nirsof@gmail.com>
8
Signed-off-by: Markus Armbruster <armbru@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
11
---
10
block/file-posix.c | 7 ++++++-
12
qobject/block-qdict.c | 14 +++++++++-----
11
1 file changed, 6 insertions(+), 1 deletion(-)
13
1 file changed, 9 insertions(+), 5 deletions(-)
12
14
13
diff --git a/block/file-posix.c b/block/file-posix.c
15
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/block/file-posix.c
17
--- a/qobject/block-qdict.c
16
+++ b/block/file-posix.c
18
+++ b/qobject/block-qdict.c
17
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
19
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
18
switch (prealloc) {
20
value = qlist_entry_obj(entry);
19
#ifdef CONFIG_POSIX_FALLOCATE
21
new_key = g_strdup_printf("%s.%i", prefix, i);
20
case PREALLOC_MODE_FALLOC:
22
21
- /* posix_fallocate() doesn't set errno. */
22
+ /*
23
+ /*
23
+ * Truncating before posix_fallocate() makes it about twice slower on
24
+ * Flatten non-empty QDict and QList recursively into @target,
24
+ * file systems that do not support fallocate(), trying to check if a
25
+ * copy other objects to @target
25
+ * block is allocated before allocating it, so don't do that here.
26
+ */
26
+ */
27
result = -posix_fallocate(fd, 0, total_size);
27
if (qobject_type(value) == QTYPE_QDICT) {
28
if (result != 0) {
28
qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
29
+ /* posix_fallocate() doesn't set errno. */
29
} else if (qobject_type(value) == QTYPE_QLIST) {
30
error_setg_errno(errp, -result,
30
qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
31
"Could not preallocate data for the new file");
31
} else {
32
- /* All other types are moved to the target unchanged. */
33
qdict_put_obj(target, new_key, qobject_ref(value));
34
}
35
36
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
37
new_key = g_strdup_printf("%s.%s", prefix, entry->key);
38
}
39
40
+ /*
41
+ * Flatten non-empty QDict and QList recursively into @target,
42
+ * copy other objects to @target
43
+ */
44
if (qobject_type(value) == QTYPE_QDICT) {
45
- /* Entries of QDicts are processed recursively, the QDict object
46
- * itself disappears. */
47
qdict_flatten_qdict(qobject_to(QDict, value), target,
48
new_key ? new_key : entry->key);
49
qdict_del(qdict, entry->key);
50
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
51
qdict_flatten_qlist(qobject_to(QList, value), target,
52
new_key ? new_key : entry->key);
53
qdict_del(qdict, entry->key);
54
- } else if (prefix) {
55
- /* All other objects are moved to the target unchanged. */
56
+ } else if (target != qdict) {
57
qdict_put_obj(target, new_key, qobject_ref(value));
58
qdict_del(qdict, entry->key);
32
}
59
}
33
--
60
--
34
1.8.3.1
61
2.13.6
35
62
36
63
diff view generated by jsdifflib
New patch
1
From: Markus Armbruster <armbru@redhat.com>
1
2
3
When you mix scalar and non-scalar keys, whether you get an "already
4
set as scalar" or an "already set as dict" error depends on qdict
5
iteration order. Neither message makes much sense. Replace by
6
""Cannot mix scalar and non-scalar keys". This is similar to the
7
message we get for mixing list and non-list keys.
8
9
I find qdict_crumple()'s first loop hard to understand. Rearrange it
10
and add a comment.
11
12
Signed-off-by: Markus Armbruster <armbru@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
qobject/block-qdict.c | 32 ++++++++++++++++----------------
16
1 file changed, 16 insertions(+), 16 deletions(-)
17
18
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/qobject/block-qdict.c
21
+++ b/qobject/block-qdict.c
22
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
23
QObject *qdict_crumple(const QDict *src, Error **errp)
24
{
25
const QDictEntry *ent;
26
- QDict *two_level, *multi_level = NULL;
27
+ QDict *two_level, *multi_level = NULL, *child_dict;
28
QObject *dst = NULL, *child;
29
size_t i;
30
char *prefix = NULL;
31
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
32
}
33
34
qdict_split_flat_key(ent->key, &prefix, &suffix);
35
-
36
child = qdict_get(two_level, prefix);
37
+ child_dict = qobject_to(QDict, child);
38
+
39
+ if (child) {
40
+ /*
41
+ * If @child_dict, then all previous keys with this prefix
42
+ * had a suffix. If @suffix, this one has one as well,
43
+ * and we're good, else there's a clash.
44
+ */
45
+ if (!child_dict || !suffix) {
46
+ error_setg(errp, "Cannot mix scalar and non-scalar keys");
47
+ goto error;
48
+ }
49
+ }
50
+
51
if (suffix) {
52
- QDict *child_dict = qobject_to(QDict, child);
53
if (!child_dict) {
54
- if (child) {
55
- error_setg(errp, "Key %s prefix is already set as a scalar",
56
- prefix);
57
- goto error;
58
- }
59
-
60
child_dict = qdict_new();
61
- qdict_put_obj(two_level, prefix, QOBJECT(child_dict));
62
+ qdict_put(two_level, prefix, child_dict);
63
}
64
-
65
qdict_put_obj(child_dict, suffix, qobject_ref(ent->value));
66
} else {
67
- if (child) {
68
- error_setg(errp, "Key %s prefix is already set as a dict",
69
- prefix);
70
- goto error;
71
- }
72
qdict_put_obj(two_level, prefix, qobject_ref(ent->value));
73
}
74
75
--
76
2.13.6
77
78
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Markus Armbruster <armbru@redhat.com>
2
2
3
In a previous commit (qemu-img: Do not truncate before preallocation) we
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
moved truncate to the PREALLOC_MODE_OFF branch to avoid slowdown in
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
posix_fallocate().
6
7
However this change is not optimal when using PREALLOC_MODE_FULL, since
8
knowing the final size from the beginning could allow the file system
9
driver to do less allocations and possibly avoid fragmentation of the
10
file.
11
12
Now we truncate also before doing full preallocation.
13
14
Signed-off-by: Nir Soffer <nirsof@gmail.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
6
---
17
block/file-posix.c | 12 ++++++++++++
7
qobject/block-qdict.c | 27 +++++++++++----------------
18
1 file changed, 12 insertions(+)
8
1 file changed, 11 insertions(+), 16 deletions(-)
19
9
20
diff --git a/block/file-posix.c b/block/file-posix.c
10
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
21
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
22
--- a/block/file-posix.c
12
--- a/qobject/block-qdict.c
23
+++ b/block/file-posix.c
13
+++ b/qobject/block-qdict.c
24
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
14
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
25
#endif
15
26
case PREALLOC_MODE_FULL:
16
for (ent = qdict_first(maybe_list); ent != NULL;
27
{
17
ent = qdict_next(maybe_list, ent)) {
28
+ /*
18
+ int is_index = !qemu_strtoi64(ent->key, NULL, 10, &val);
29
+ * Knowing the final size from the beginning could allow the file
19
30
+ * system driver to do less allocations and possibly avoid
20
- if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
31
+ * fragmentation of the file.
21
- if (is_list == -1) {
32
+ */
22
- is_list = 1;
33
+ if (ftruncate(fd, total_size) != 0) {
23
- } else if (!is_list) {
34
+ result = -errno;
24
- error_setg(errp,
35
+ error_setg_errno(errp, -result, "Could not resize file");
25
- "Cannot mix list and non-list keys");
36
+ goto out_close;
26
- return -1;
27
- }
28
+ if (is_list == -1) {
29
+ is_list = is_index;
37
+ }
30
+ }
38
+
31
+
39
int64_t num = 0, left = total_size;
32
+ if (is_index != is_list) {
40
buf = g_malloc0(65536);
33
+ error_setg(errp, "Cannot mix list and non-list keys");
41
34
+ return -1;
42
@@ -XXX,XX +XXX,XX @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
35
+ }
43
break;
36
+
37
+ if (is_index) {
38
len++;
39
if (val > max) {
40
max = val;
41
}
42
- } else {
43
- if (is_list == -1) {
44
- is_list = 0;
45
- } else if (is_list) {
46
- error_setg(errp,
47
- "Cannot mix list and non-list keys");
48
- return -1;
49
- }
50
}
44
}
51
}
45
52
46
+out_close:
47
if (qemu_close(fd) != 0 && result == 0) {
48
result = -errno;
49
error_setg_errno(errp, -result, "Could not close the new file");
50
--
53
--
51
1.8.3.1
54
2.13.6
52
55
53
56
diff view generated by jsdifflib
1
From: Jeff Cody <jcody@redhat.com>
1
From: Markus Armbruster <armbru@redhat.com>
2
2
3
Add the ability for shell script tests to exclude specific
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
protocols. This is useful to allow all protocols except ones known to
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
not support a feature used in the test (e.g. .bdrv_create).
6
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
6
---
10
tests/qemu-iotests/common.rc | 12 ++++++++++++
7
tests/check-block-qdict.c | 57 ++++++++++++++++++++++++-----------------------
11
1 file changed, 12 insertions(+)
8
1 file changed, 29 insertions(+), 28 deletions(-)
12
9
13
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
10
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
14
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/common.rc
12
--- a/tests/check-block-qdict.c
16
+++ b/tests/qemu-iotests/common.rc
13
+++ b/tests/check-block-qdict.c
17
@@ -XXX,XX +XXX,XX @@ _supported_proto()
14
@@ -XXX,XX +XXX,XX @@ static void qdict_defaults_test(void)
18
_notrun "not suitable for this image protocol: $IMGPROTO"
15
16
static void qdict_flatten_test(void)
17
{
18
- QList *list1 = qlist_new();
19
- QList *list2 = qlist_new();
20
- QDict *dict1 = qdict_new();
21
- QDict *dict2 = qdict_new();
22
- QDict *dict3 = qdict_new();
23
+ QList *e_1 = qlist_new();
24
+ QList *e = qlist_new();
25
+ QDict *e_1_2 = qdict_new();
26
+ QDict *f = qdict_new();
27
+ QDict *root = qdict_new();
28
29
/*
30
* Test the flattening of
31
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
32
* }
33
*/
34
35
- qdict_put_int(dict1, "a", 0);
36
- qdict_put_int(dict1, "b", 1);
37
+ qdict_put_int(e_1_2, "a", 0);
38
+ qdict_put_int(e_1_2, "b", 1);
39
40
- qlist_append_int(list1, 23);
41
- qlist_append_int(list1, 66);
42
- qlist_append(list1, dict1);
43
- qlist_append_int(list2, 42);
44
- qlist_append(list2, list1);
45
+ qlist_append_int(e_1, 23);
46
+ qlist_append_int(e_1, 66);
47
+ qlist_append(e_1, e_1_2);
48
+ qlist_append_int(e, 42);
49
+ qlist_append(e, e_1);
50
51
- qdict_put_int(dict2, "c", 2);
52
- qdict_put_int(dict2, "d", 3);
53
- qdict_put(dict3, "e", list2);
54
- qdict_put(dict3, "f", dict2);
55
- qdict_put_int(dict3, "g", 4);
56
+ qdict_put_int(f, "c", 2);
57
+ qdict_put_int(f, "d", 3);
58
59
- qdict_flatten(dict3);
60
+ qdict_put(root, "e", e);
61
+ qdict_put(root, "f", f);
62
+ qdict_put_int(root, "g", 4);
63
64
- g_assert(qdict_get_int(dict3, "e.0") == 42);
65
- g_assert(qdict_get_int(dict3, "e.1.0") == 23);
66
- g_assert(qdict_get_int(dict3, "e.1.1") == 66);
67
- g_assert(qdict_get_int(dict3, "e.1.2.a") == 0);
68
- g_assert(qdict_get_int(dict3, "e.1.2.b") == 1);
69
- g_assert(qdict_get_int(dict3, "f.c") == 2);
70
- g_assert(qdict_get_int(dict3, "f.d") == 3);
71
- g_assert(qdict_get_int(dict3, "g") == 4);
72
+ qdict_flatten(root);
73
74
- g_assert(qdict_size(dict3) == 8);
75
+ g_assert(qdict_get_int(root, "e.0") == 42);
76
+ g_assert(qdict_get_int(root, "e.1.0") == 23);
77
+ g_assert(qdict_get_int(root, "e.1.1") == 66);
78
+ g_assert(qdict_get_int(root, "e.1.2.a") == 0);
79
+ g_assert(qdict_get_int(root, "e.1.2.b") == 1);
80
+ g_assert(qdict_get_int(root, "f.c") == 2);
81
+ g_assert(qdict_get_int(root, "f.d") == 3);
82
+ g_assert(qdict_get_int(root, "g") == 4);
83
84
- qobject_unref(dict3);
85
+ g_assert(qdict_size(root) == 8);
86
+
87
+ qobject_unref(root);
19
}
88
}
20
89
21
+# tests whether $IMGPROTO is specified as an unsupported image protocol for a test
90
static void qdict_array_split_test(void)
22
+#
23
+_unsupported_proto()
24
+{
25
+ for f; do
26
+ if [ "$f" = "$IMGPROTO" ]; then
27
+ _notrun "not suitable for this image protocol: $IMGPROTO"
28
+ return
29
+ fi
30
+ done
31
+}
32
+
33
# tests whether the host OS is one of the supported OSes for a test
34
#
35
_supported_os()
36
--
91
--
37
1.8.3.1
92
2.13.6
38
93
39
94
diff view generated by jsdifflib
1
From: Jeff Cody <jcody@redhat.com>
1
From: Markus Armbruster <armbru@redhat.com>
2
2
3
Since test 137 make uses of qcow2.py, only local files are supported.
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
6
---
8
tests/qemu-iotests/137 | 2 +-
7
tests/check-block-qdict.c | 14 +++++++++++++-
9
1 file changed, 1 insertion(+), 1 deletion(-)
8
1 file changed, 13 insertions(+), 1 deletion(-)
10
9
11
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
10
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
12
index XXXXXXX..XXXXXXX 100755
11
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/137
12
--- a/tests/check-block-qdict.c
14
+++ b/tests/qemu-iotests/137
13
+++ b/tests/check-block-qdict.c
15
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
14
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
16
. ./common.qemu
15
QList *e = qlist_new();
17
16
QDict *e_1_2 = qdict_new();
18
_supported_fmt qcow2
17
QDict *f = qdict_new();
19
-_supported_proto generic
18
+ QList *y = qlist_new();
20
+_supported_proto file
19
+ QDict *z = qdict_new();
21
_supported_os Linux
20
QDict *root = qdict_new();
22
21
22
/*
23
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
24
* "c": 2,
25
* "d": 3,
26
* },
27
- * "g": 4
28
+ * "g": 4,
29
+ * "y": [{}],
30
+ * "z": {"a": []}
31
* }
32
*
33
* to
34
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
35
* "f.d": 3,
36
* "g": 4
37
* }
38
+ *
39
+ * Note that "y" and "z" get eaten.
40
*/
41
42
qdict_put_int(e_1_2, "a", 0);
43
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
44
qdict_put_int(f, "c", 2);
45
qdict_put_int(f, "d", 3);
46
47
+ qlist_append(y, qdict_new());
48
+
49
+ qdict_put(z, "a", qlist_new());
50
+
51
qdict_put(root, "e", e);
52
qdict_put(root, "f", f);
53
qdict_put_int(root, "g", 4);
54
+ qdict_put(root, "y", y);
55
+ qdict_put(root, "z", z);
56
57
qdict_flatten(root);
23
58
24
--
59
--
25
1.8.3.1
60
2.13.6
26
61
27
62
diff view generated by jsdifflib
New patch
1
1
From: Markus Armbruster <armbru@redhat.com>
2
3
-blockdev and blockdev-add silently ignore empty objects and arrays in
4
their argument. That's because qmp_blockdev_add() converts the
5
argument to a flat QDict, and qdict_flatten() eats empty QDict and
6
QList members. For instance, we ignore an empty BlockdevOptions
7
member @cache. No real harm, as absent means the same as empty there.
8
9
Thus, the flaw puts an artificial restriction on the QAPI schema: we
10
can't have potentially empty objects and arrays within
11
BlockdevOptions, except when they're optional and "empty" has the same
12
meaning as "absent".
13
14
Our QAPI schema satisfies this restriction (I checked), but it's a
15
trap for the unwary, and a temptation to employ awkward workarounds
16
for the wary. Let's get rid of it.
17
18
Change qdict_flatten() and qdict_crumple() to treat empty dictionaries
19
and lists exactly like scalars.
20
21
Signed-off-by: Markus Armbruster <armbru@redhat.com>
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
25
qobject/block-qdict.c | 54 +++++++++++++++++++++++++++++------------------
26
tests/check-block-qdict.c | 38 ++++++++++++++++++++++++++-------
27
2 files changed, 63 insertions(+), 29 deletions(-)
28
29
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/qobject/block-qdict.c
32
+++ b/qobject/block-qdict.c
33
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
34
{
35
QObject *value;
36
const QListEntry *entry;
37
+ QDict *dict_val;
38
+ QList *list_val;
39
char *new_key;
40
int i;
41
42
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
43
44
for (i = 0; entry; entry = qlist_next(entry), i++) {
45
value = qlist_entry_obj(entry);
46
+ dict_val = qobject_to(QDict, value);
47
+ list_val = qobject_to(QList, value);
48
new_key = g_strdup_printf("%s.%i", prefix, i);
49
50
/*
51
* Flatten non-empty QDict and QList recursively into @target,
52
* copy other objects to @target
53
*/
54
- if (qobject_type(value) == QTYPE_QDICT) {
55
- qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
56
- } else if (qobject_type(value) == QTYPE_QLIST) {
57
- qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
58
+ if (dict_val && qdict_size(dict_val)) {
59
+ qdict_flatten_qdict(dict_val, target, new_key);
60
+ } else if (list_val && !qlist_empty(list_val)) {
61
+ qdict_flatten_qlist(list_val, target, new_key);
62
} else {
63
qdict_put_obj(target, new_key, qobject_ref(value));
64
}
65
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
66
{
67
QObject *value;
68
const QDictEntry *entry, *next;
69
+ QDict *dict_val;
70
+ QList *list_val;
71
char *new_key;
72
73
entry = qdict_first(qdict);
74
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
75
while (entry != NULL) {
76
next = qdict_next(qdict, entry);
77
value = qdict_entry_value(entry);
78
+ dict_val = qobject_to(QDict, value);
79
+ list_val = qobject_to(QList, value);
80
new_key = NULL;
81
82
if (prefix) {
83
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
84
* Flatten non-empty QDict and QList recursively into @target,
85
* copy other objects to @target
86
*/
87
- if (qobject_type(value) == QTYPE_QDICT) {
88
- qdict_flatten_qdict(qobject_to(QDict, value), target,
89
+ if (dict_val && qdict_size(dict_val)) {
90
+ qdict_flatten_qdict(dict_val, target,
91
new_key ? new_key : entry->key);
92
qdict_del(qdict, entry->key);
93
- } else if (qobject_type(value) == QTYPE_QLIST) {
94
- qdict_flatten_qlist(qobject_to(QList, value), target,
95
+ } else if (list_val && !qlist_empty(list_val)) {
96
+ qdict_flatten_qlist(list_val, target,
97
new_key ? new_key : entry->key);
98
qdict_del(qdict, entry->key);
99
} else if (target != qdict) {
100
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
101
}
102
103
/**
104
- * qdict_flatten(): For each nested QDict with key x, all fields with key y
105
- * are moved to this QDict and their key is renamed to "x.y". For each nested
106
- * QList with key x, the field at index y is moved to this QDict with the key
107
- * "x.y" (i.e., the reverse of what qdict_array_split() does).
108
+ * qdict_flatten(): For each nested non-empty QDict with key x, all
109
+ * fields with key y are moved to this QDict and their key is renamed
110
+ * to "x.y". For each nested non-empty QList with key x, the field at
111
+ * index y is moved to this QDict with the key "x.y" (i.e., the
112
+ * reverse of what qdict_array_split() does).
113
* This operation is applied recursively for nested QDicts and QLists.
114
*/
115
void qdict_flatten(QDict *qdict)
116
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
117
* @src: the original flat dictionary (only scalar values) to crumple
118
*
119
* Takes a flat dictionary whose keys use '.' separator to indicate
120
- * nesting, and values are scalars, and crumples it into a nested
121
- * structure.
122
+ * nesting, and values are scalars, empty dictionaries or empty lists,
123
+ * and crumples it into a nested structure.
124
*
125
* To include a literal '.' in a key name, it must be escaped as '..'
126
*
127
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
128
{
129
const QDictEntry *ent;
130
QDict *two_level, *multi_level = NULL, *child_dict;
131
+ QDict *dict_val;
132
+ QList *list_val;
133
QObject *dst = NULL, *child;
134
size_t i;
135
char *prefix = NULL;
136
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
137
138
/* Step 1: split our totally flat dict into a two level dict */
139
for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) {
140
- if (qobject_type(ent->value) == QTYPE_QDICT ||
141
- qobject_type(ent->value) == QTYPE_QLIST) {
142
- error_setg(errp, "Value %s is not a scalar",
143
- ent->key);
144
+ dict_val = qobject_to(QDict, ent->value);
145
+ list_val = qobject_to(QList, ent->value);
146
+ if ((dict_val && qdict_size(dict_val))
147
+ || (list_val && !qlist_empty(list_val))) {
148
+ error_setg(errp, "Value %s is not flat", ent->key);
149
goto error;
150
}
151
152
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
153
multi_level = qdict_new();
154
for (ent = qdict_first(two_level); ent != NULL;
155
ent = qdict_next(two_level, ent)) {
156
- QDict *dict = qobject_to(QDict, ent->value);
157
- if (dict) {
158
- child = qdict_crumple(dict, errp);
159
+ dict_val = qobject_to(QDict, ent->value);
160
+ if (dict_val && qdict_size(dict_val)) {
161
+ child = qdict_crumple(dict_val, errp);
162
if (!child) {
163
goto error;
164
}
165
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/tests/check-block-qdict.c
168
+++ b/tests/check-block-qdict.c
169
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
170
* "e.1.2.b": 1,
171
* "f.c": 2,
172
* "f.d": 3,
173
- * "g": 4
174
+ * "g": 4,
175
+ * "y.0": {},
176
+ * "z.a": []
177
* }
178
- *
179
- * Note that "y" and "z" get eaten.
180
*/
181
182
qdict_put_int(e_1_2, "a", 0);
183
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
184
g_assert(qdict_get_int(root, "f.c") == 2);
185
g_assert(qdict_get_int(root, "f.d") == 3);
186
g_assert(qdict_get_int(root, "g") == 4);
187
+ g_assert(!qdict_size(qdict_get_qdict(root, "y.0")));
188
+ g_assert(qlist_empty(qdict_get_qlist(root, "z.a")));
189
190
- g_assert(qdict_size(root) == 8);
191
+ g_assert(qdict_size(root) == 10);
192
193
qobject_unref(root);
194
}
195
@@ -XXX,XX +XXX,XX @@ static void qdict_join_test(void)
196
static void qdict_crumple_test_recursive(void)
197
{
198
QDict *src, *dst, *rule, *vnc, *acl, *listen;
199
- QList *rules;
200
+ QDict *empty, *empty_dict, *empty_list_0;
201
+ QList *rules, *empty_list, *empty_dict_a;
202
203
src = qdict_new();
204
qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
205
@@ -XXX,XX +XXX,XX @@ static void qdict_crumple_test_recursive(void)
206
qdict_put_str(src, "vnc.acl.default", "deny");
207
qdict_put_str(src, "vnc.acl..name", "acl0");
208
qdict_put_str(src, "vnc.acl.rule..name", "acl0");
209
+ qdict_put(src, "empty.dict.a", qlist_new());
210
+ qdict_put(src, "empty.list.0", qdict_new());
211
212
dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
213
g_assert(dst);
214
- g_assert_cmpint(qdict_size(dst), ==, 1);
215
+ g_assert_cmpint(qdict_size(dst), ==, 2);
216
217
vnc = qdict_get_qdict(dst, "vnc");
218
g_assert(vnc);
219
@@ -XXX,XX +XXX,XX @@ static void qdict_crumple_test_recursive(void)
220
g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
221
g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
222
223
+ empty = qdict_get_qdict(dst, "empty");
224
+ g_assert(empty);
225
+ g_assert_cmpint(qdict_size(empty), ==, 2);
226
+ empty_dict = qdict_get_qdict(empty, "dict");
227
+ g_assert(empty_dict);
228
+ g_assert_cmpint(qdict_size(empty_dict), ==, 1);
229
+ empty_dict_a = qdict_get_qlist(empty_dict, "a");
230
+ g_assert(empty_dict_a && qlist_empty(empty_dict_a));
231
+ empty_list = qdict_get_qlist(empty, "list");
232
+ g_assert(empty_list);
233
+ g_assert_cmpint(qlist_size(empty_list), ==, 1);
234
+ empty_list_0 = qobject_to(QDict, qlist_pop(empty_list));
235
+ g_assert(empty_list_0);
236
+ g_assert_cmpint(qdict_size(empty_list_0), ==, 0);
237
+
238
qobject_unref(src);
239
qobject_unref(dst);
240
}
241
@@ -XXX,XX +XXX,XX @@ static void qdict_rename_keys_test(void)
242
243
static void qdict_crumple_test_bad_inputs(void)
244
{
245
- QDict *src;
246
+ QDict *src, *nested;
247
Error *error = NULL;
248
249
src = qdict_new();
250
@@ -XXX,XX +XXX,XX @@ static void qdict_crumple_test_bad_inputs(void)
251
252
src = qdict_new();
253
/* The input should be flat, ie no dicts or lists */
254
- qdict_put(src, "rule.a", qdict_new());
255
+ nested = qdict_new();
256
+ qdict_put(nested, "x", qdict_new());
257
+ qdict_put(src, "rule.a", nested);
258
qdict_put_str(src, "rule.b", "allow");
259
260
g_assert(qdict_crumple(src, &error) == NULL);
261
--
262
2.13.6
263
264
diff view generated by jsdifflib
1
This function allows to create more or less normal BlockDriverStates
1
From: Markus Armbruster <armbru@redhat.com>
2
even for BlockDrivers that aren't globally registered (e.g. helper
3
filters for block jobs).
4
2
3
Parameter auth-client-required lets you configure authentication
4
methods. We tried to provide that in v2.9.0, but backed out due to
5
interface design doubts (commit 464444fcc16).
6
7
This commit is similar to what we backed out, but simpler: we use a
8
list of enumeration values instead of a list of objects with a member
9
of enumeration type.
10
11
Let's review our reasons for backing out the first try, as stated in
12
the commit message:
13
14
* The implementation uses deprecated rados_conf_set() key
15
"auth_supported". No biggie.
16
17
Fixed: we use "auth-client-required".
18
19
* The implementation makes -drive silently ignore invalid parameters
20
"auth" and "auth-supported.*.X" where X isn't "auth". Fixable (in
21
fact I'm going to fix similar bugs around parameter server), so
22
again no biggie.
23
24
That fix is commit 2836284db60. This commit doesn't bring the bugs
25
back.
26
27
* BlockdevOptionsRbd member @password-secret applies only to
28
authentication method cephx. Should it be a variant member of
29
RbdAuthMethod?
30
31
We've had time to ponder, and we decided to stick to the way Ceph
32
configuration works: the key configured separately, and silently
33
ignored if the authentication method doesn't use it.
34
35
* BlockdevOptionsRbd member @user could apply to both methods cephx
36
and none, but I'm not sure it's actually used with none. If it
37
isn't, should it be a variant member of RbdAuthMethod?
38
39
Likewise.
40
41
* The client offers a *set* of authentication methods, not a list.
42
Should the methods be optional members of BlockdevOptionsRbd instead
43
of members of list @auth-supported? The latter begs the question
44
what multiple entries for the same method mean. Trivial question
45
now that RbdAuthMethod contains nothing but @type, but less so when
46
RbdAuthMethod acquires other members, such the ones discussed above.
47
48
Again, we decided to stick to the way Ceph configuration works, except
49
we make auth-client-required a list of enumeration values instead of a
50
string containing keywords separated by delimiters.
51
52
* How BlockdevOptionsRbd member @auth-supported interacts with
53
settings from a configuration file specified with @conf is
54
undocumented. I suspect it's untested, too.
55
56
Not actually true, the documentation for @conf says "Values in the
57
configuration file will be overridden by options specified via QAPI",
58
and we've tested this.
59
60
Signed-off-by: Markus Armbruster <armbru@redhat.com>
61
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
62
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
63
---
8
block.c | 30 +++++++++++++++++++++++++++++-
64
qapi/block-core.json | 13 +++++++++++++
9
include/block/block.h | 2 ++
65
block/rbd.c | 42 ++++++++++++++++++++++++++++++++----------
10
2 files changed, 31 insertions(+), 1 deletion(-)
66
2 files changed, 45 insertions(+), 10 deletions(-)
11
67
12
diff --git a/block.c b/block.c
68
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
index XXXXXXX..XXXXXXX 100644
69
index XXXXXXX..XXXXXXX 100644
14
--- a/block.c
70
--- a/qapi/block-core.json
15
+++ b/block.c
71
+++ b/qapi/block-core.json
16
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
72
@@ -XXX,XX +XXX,XX @@
73
74
75
##
76
+# @RbdAuthMode:
77
+#
78
+# Since: 3.0
79
+##
80
+{ 'enum': 'RbdAuthMode',
81
+ 'data': [ 'cephx', 'none' ] }
82
+
83
+##
84
# @BlockdevOptionsRbd:
85
#
86
# @pool: Ceph pool name.
87
@@ -XXX,XX +XXX,XX @@
88
#
89
# @user: Ceph id name.
90
#
91
+# @auth-client-required: Acceptable authentication modes.
92
+# This maps to Ceph configuration option
93
+# "auth_client_required". (Since 3.0)
94
+#
95
# @server: Monitor host address and port. This maps
96
# to the "mon_host" Ceph option.
97
#
98
@@ -XXX,XX +XXX,XX @@
99
'*conf': 'str',
100
'*snapshot': 'str',
101
'*user': 'str',
102
+ '*auth-client-required': ['RbdAuthMode'],
103
'*server': ['InetSocketAddressBase'] } }
104
105
##
106
diff --git a/block/rbd.c b/block/rbd.c
107
index XXXXXXX..XXXXXXX 100644
108
--- a/block/rbd.c
109
+++ b/block/rbd.c
110
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_refresh_limits(BlockDriverState *bs, Error **errp)
111
112
113
static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
114
+ BlockdevOptionsRbd *opts,
115
Error **errp)
116
{
117
- if (secretid == 0) {
118
- return 0;
119
- }
120
+ char *acr;
121
+ int r;
122
+ GString *accu;
123
+ RbdAuthModeList *auth;
124
+
125
+ if (secretid) {
126
+ gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
127
+ errp);
128
+ if (!secret) {
129
+ return -1;
130
+ }
131
132
- gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
133
- errp);
134
- if (!secret) {
135
- return -1;
136
+ rados_conf_set(cluster, "key", secret);
137
+ g_free(secret);
17
}
138
}
18
139
19
bs->drv = drv;
140
- rados_conf_set(cluster, "key", secret);
20
+ bs->read_only = !(bs->open_flags & BDRV_O_RDWR);
141
- g_free(secret);
21
bs->opaque = g_malloc0(drv->instance_size);
142
+ if (opts->has_auth_client_required) {
22
143
+ accu = g_string_new("");
23
if (drv->bdrv_file_open) {
144
+ for (auth = opts->auth_client_required; auth; auth = auth->next) {
24
assert(!drv->bdrv_needs_filename || bs->filename[0]);
145
+ if (accu->str[0]) {
25
ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
146
+ g_string_append_c(accu, ';');
26
- } else {
147
+ }
27
+ } else if (drv->bdrv_open) {
148
+ g_string_append(accu, RbdAuthMode_str(auth->value));
28
ret = drv->bdrv_open(bs, options, open_flags, &local_err);
149
+ }
29
+ } else {
150
+ acr = g_string_free(accu, FALSE);
30
+ ret = 0;
151
+ r = rados_conf_set(cluster, "auth_client_required", acr);
152
+ g_free(acr);
153
+ if (r < 0) {
154
+ error_setg_errno(errp, -r,
155
+ "Could not set 'auth_client_required'");
156
+ return r;
157
+ }
158
+ }
159
160
return 0;
161
}
162
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
163
}
31
}
164
}
32
165
33
if (ret < 0) {
166
- if (qemu_rbd_set_auth(*cluster, secretid, errp) < 0) {
34
@@ -XXX,XX +XXX,XX @@ free_and_fail:
167
+ if (qemu_rbd_set_auth(*cluster, secretid, opts, errp) < 0) {
35
return ret;
168
r = -EIO;
36
}
169
goto failed_shutdown;
37
170
}
38
+BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
39
+ int flags, Error **errp)
40
+{
41
+ BlockDriverState *bs;
42
+ int ret;
43
+
44
+ bs = bdrv_new();
45
+ bs->open_flags = flags;
46
+ bs->explicit_options = qdict_new();
47
+ bs->options = qdict_new();
48
+ bs->opaque = NULL;
49
+
50
+ update_options_from_flags(bs->options, flags);
51
+
52
+ ret = bdrv_open_driver(bs, drv, node_name, bs->options, flags, errp);
53
+ if (ret < 0) {
54
+ QDECREF(bs->explicit_options);
55
+ QDECREF(bs->options);
56
+ bdrv_unref(bs);
57
+ return NULL;
58
+ }
59
+
60
+ return bs;
61
+}
62
+
63
QemuOptsList bdrv_runtime_opts = {
64
.name = "bdrv_common",
65
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
66
diff --git a/include/block/block.h b/include/block/block.h
67
index XXXXXXX..XXXXXXX 100644
68
--- a/include/block/block.h
69
+++ b/include/block/block.h
70
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
71
const char *bdref_key, Error **errp);
72
BlockDriverState *bdrv_open(const char *filename, const char *reference,
73
QDict *options, int flags, Error **errp);
74
+BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
75
+ int flags, Error **errp);
76
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
77
BlockDriverState *bs,
78
QDict *options, int flags);
79
--
171
--
80
1.8.3.1
172
2.13.6
81
173
82
174
diff view generated by jsdifflib
1
This fixes the use of a parent-less BdrvChild in bdrv_open_inherit() by
1
From: Markus Armbruster <armbru@redhat.com>
2
converting it into a BlockBackend. Which is exactly what it should be,
3
image probing is an external, standalone user of a node. The requests
4
can't be considered to originate from the format driver node because
5
that one isn't even opened yet.
6
2
3
Legacy -drive supports "password-secret" parameter that isn't
4
available with -blockdev / blockdev-add. That's because we backed out
5
our first try to provide it there due to interface design doubts, in
6
commit 577d8c9a811, v2.9.0.
7
8
This is the second try. It brings back the parameter, except it's
9
named "key-secret" now.
10
11
Let's review our reasons for backing out the first try, as stated in
12
the commit message:
13
14
* BlockdevOptionsRbd member @password-secret isn't actually a
15
password, it's a key generated by Ceph.
16
17
Addressed by the rename.
18
19
* We're not sure where member @password-secret belongs (see the
20
previous commit).
21
22
See previous commit.
23
24
* How @password-secret interacts with settings from a configuration
25
file specified with @conf is undocumented.
26
27
Not actually true, the documentation for @conf says "Values in the
28
configuration file will be overridden by options specified via QAPI",
29
and we've tested this.
30
31
Signed-off-by: Markus Armbruster <armbru@redhat.com>
32
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
33
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
34
---
10
block.c | 36 +++++++++++++++++++-----------------
35
qapi/block-core.json | 6 ++++++
11
1 file changed, 19 insertions(+), 17 deletions(-)
36
block/rbd.c | 41 +++++++++++++++++++++++++----------------
37
2 files changed, 31 insertions(+), 16 deletions(-)
12
38
13
diff --git a/block.c b/block.c
39
diff --git a/qapi/block-core.json b/qapi/block-core.json
14
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
41
--- a/qapi/block-core.json
16
+++ b/block.c
42
+++ b/qapi/block-core.json
17
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
43
@@ -XXX,XX +XXX,XX @@
18
return drv;
44
# This maps to Ceph configuration option
45
# "auth_client_required". (Since 3.0)
46
#
47
+# @key-secret: ID of a QCryptoSecret object providing a key
48
+# for cephx authentication.
49
+# This maps to Ceph configuration option
50
+# "key". (Since 3.0)
51
+#
52
# @server: Monitor host address and port. This maps
53
# to the "mon_host" Ceph option.
54
#
55
@@ -XXX,XX +XXX,XX @@
56
'*snapshot': 'str',
57
'*user': 'str',
58
'*auth-client-required': ['RbdAuthMode'],
59
+ '*key-secret': 'str',
60
'*server': ['InetSocketAddressBase'] } }
61
62
##
63
diff --git a/block/rbd.c b/block/rbd.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/block/rbd.c
66
+++ b/block/rbd.c
67
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_refresh_limits(BlockDriverState *bs, Error **errp)
19
}
68
}
20
69
21
-static int find_image_format(BdrvChild *file, const char *filename,
70
22
+static int find_image_format(BlockBackend *file, const char *filename,
71
-static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
23
BlockDriver **pdrv, Error **errp)
72
- BlockdevOptionsRbd *opts,
73
+static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts,
74
Error **errp)
24
{
75
{
25
- BlockDriverState *bs = file->bs;
76
- char *acr;
26
BlockDriver *drv;
77
+ char *key, *acr;
27
uint8_t buf[BLOCK_PROBE_BUF_SIZE];
78
int r;
28
int ret = 0;
79
GString *accu;
29
80
RbdAuthModeList *auth;
30
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
81
31
- if (bdrv_is_sg(bs) || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
82
- if (secretid) {
32
+ if (blk_is_sg(file) || !blk_is_inserted(file) || blk_getlength(file) == 0) {
83
- gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
33
*pdrv = &bdrv_raw;
84
- errp);
34
return ret;
85
- if (!secret) {
86
- return -1;
87
+ if (opts->key_secret) {
88
+ key = qcrypto_secret_lookup_as_base64(opts->key_secret, errp);
89
+ if (!key) {
90
+ return -EIO;
91
+ }
92
+ r = rados_conf_set(cluster, "key", key);
93
+ g_free(key);
94
+ if (r < 0) {
95
+ error_setg_errno(errp, -r, "Could not set 'key'");
96
+ return r;
97
}
98
-
99
- rados_conf_set(cluster, "key", secret);
100
- g_free(secret);
35
}
101
}
36
102
37
- ret = bdrv_pread(file, 0, buf, sizeof(buf));
103
if (opts->has_auth_client_required) {
38
+ ret = blk_pread(file, 0, buf, sizeof(buf));
104
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
39
if (ret < 0) {
105
},
40
error_setg_errno(errp, -ret, "Could not read image for determining its "
106
};
41
"format");
107
42
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
108
-/* FIXME Deprecate and remove keypairs or make it available in QMP.
43
*
109
- * password_secret should eventually be configurable in opts->location. Support
44
* Removes all processed options from *options.
110
- * for it in .bdrv_open will make it work here as well. */
45
*/
111
+/* FIXME Deprecate and remove keypairs or make it available in QMP. */
46
-static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
112
static int qemu_rbd_do_create(BlockdevCreateOptions *options,
47
+static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
113
const char *keypairs, const char *password_secret,
48
QDict *options, Error **errp)
114
Error **errp)
49
{
115
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
50
int ret, open_flags;
116
Error *local_err = NULL;
51
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
117
int r;
52
assert(drv != NULL);
118
53
119
+ if (secretid) {
54
if (file != NULL) {
120
+ if (opts->key_secret) {
55
- filename = file->bs->filename;
121
+ error_setg(errp,
56
+ filename = blk_bs(file)->filename;
122
+ "Legacy 'password-secret' clashes with 'key-secret'");
57
} else {
123
+ return -EINVAL;
58
filename = qdict_get_try_str(options, "filename");
124
+ }
59
}
125
+ opts->key_secret = g_strdup(secretid);
60
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
126
+ opts->has_key_secret = true;
61
Error **errp)
127
+ }
62
{
63
int ret;
64
- BdrvChild *file = NULL;
65
+ BlockBackend *file = NULL;
66
BlockDriverState *bs;
67
BlockDriver *drv = NULL;
68
const char *drvname;
69
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
70
qdict_del(options, "backing");
71
}
72
73
- /* Open image file without format layer. This BdrvChild is only used for
74
+ /* Open image file without format layer. This BlockBackend is only used for
75
* probing, the block drivers will do their own bdrv_open_child() for the
76
* same BDS, which is why we put the node name back into options. */
77
if ((flags & BDRV_O_PROTOCOL) == 0) {
78
- /* FIXME Shouldn't attach a child to a node that isn't opened yet. */
79
- file = bdrv_open_child(filename, options, "file", bs,
80
- &child_file, true, &local_err);
81
+ BlockDriverState *file_bs;
82
+
128
+
83
+ file_bs = bdrv_open_child_bs(filename, options, "file", bs,
129
mon_host = qemu_rbd_mon_host(opts, &local_err);
84
+ &child_file, true, &local_err);
130
if (local_err) {
85
if (local_err) {
131
error_propagate(errp, local_err);
86
goto fail;
132
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
87
}
88
- if (file != NULL) {
89
+ if (file_bs != NULL) {
90
+ file = blk_new();
91
+ blk_insert_bs(file, file_bs);
92
+ bdrv_unref(file_bs);
93
+
94
qdict_put(options, "file",
95
- qstring_from_str(bdrv_get_node_name(file->bs)));
96
+ qstring_from_str(bdrv_get_node_name(file_bs)));
97
}
133
}
98
}
134
}
99
135
100
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
136
- if (qemu_rbd_set_auth(*cluster, secretid, opts, errp) < 0) {
137
- r = -EIO;
138
+ r = qemu_rbd_set_auth(*cluster, opts, errp);
139
+ if (r < 0) {
140
goto failed_shutdown;
101
}
141
}
102
142
103
if (file) {
104
- bdrv_unref_child(bs, file);
105
+ blk_unref(file);
106
file = NULL;
107
}
108
109
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
110
return bs;
111
112
fail:
113
- if (file != NULL) {
114
- bdrv_unref_child(bs, file);
115
- }
116
+ blk_unref(file);
117
if (bs->file != NULL) {
118
bdrv_unref_child(bs, bs->file);
119
}
120
--
143
--
121
1.8.3.1
144
2.13.6
122
145
123
146
diff view generated by jsdifflib
New patch
1
1
The -drive options cyls, heads, secs and trans were deprecated in
2
QEMU 2.10. It's time to remove them.
3
4
hd-geo-test tested both the old version with geometry options in -drive
5
and the new one with -device. Therefore the code using -drive doesn't
6
have to be replaced there, we just need to remove the -drive test cases.
7
This in turn allows some simplification of the code.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
---
12
include/sysemu/blockdev.h | 1 -
13
blockdev.c | 75 +----------------------------------------------
14
hw/block/block.c | 14 ---------
15
tests/hd-geo-test.c | 37 +++++------------------
16
hmp-commands.hx | 1 -
17
qemu-doc.texi | 5 ----
18
qemu-options.hx | 7 +----
19
7 files changed, 9 insertions(+), 131 deletions(-)
20
21
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/sysemu/blockdev.h
24
+++ b/include/sysemu/blockdev.h
25
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
26
int auto_del; /* see blockdev_mark_auto_del() */
27
bool is_default; /* Added by default_drive() ? */
28
int media_cd;
29
- int cyls, heads, secs, trans;
30
QemuOpts *opts;
31
char *serial;
32
QTAILQ_ENTRY(DriveInfo) next;
33
diff --git a/blockdev.c b/blockdev.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/blockdev.c
36
+++ b/blockdev.c
37
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
38
.type = QEMU_OPT_STRING,
39
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
40
},{
41
- .name = "cyls",
42
- .type = QEMU_OPT_NUMBER,
43
- .help = "number of cylinders (ide disk geometry)",
44
- },{
45
- .name = "heads",
46
- .type = QEMU_OPT_NUMBER,
47
- .help = "number of heads (ide disk geometry)",
48
- },{
49
- .name = "secs",
50
- .type = QEMU_OPT_NUMBER,
51
- .help = "number of sectors (ide disk geometry)",
52
- },{
53
- .name = "trans",
54
- .type = QEMU_OPT_STRING,
55
- .help = "chs translation (auto, lba, none)",
56
- },{
57
.name = "addr",
58
.type = QEMU_OPT_STRING,
59
.help = "pci address (virtio only)",
60
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
61
QemuOpts *legacy_opts;
62
DriveMediaType media = MEDIA_DISK;
63
BlockInterfaceType type;
64
- int cyls, heads, secs, translation;
65
int max_devs, bus_id, unit_id, index;
66
const char *devaddr;
67
const char *werror, *rerror;
68
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
69
Error *local_err = NULL;
70
int i;
71
const char *deprecated[] = {
72
- "serial", "trans", "secs", "heads", "cyls", "addr"
73
+ "serial", "addr"
74
};
75
76
/* Change legacy command line options into QMP ones */
77
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
78
type = block_default_type;
79
}
80
81
- /* Geometry */
82
- cyls = qemu_opt_get_number(legacy_opts, "cyls", 0);
83
- heads = qemu_opt_get_number(legacy_opts, "heads", 0);
84
- secs = qemu_opt_get_number(legacy_opts, "secs", 0);
85
-
86
- if (cyls || heads || secs) {
87
- if (cyls < 1) {
88
- error_report("invalid physical cyls number");
89
- goto fail;
90
- }
91
- if (heads < 1) {
92
- error_report("invalid physical heads number");
93
- goto fail;
94
- }
95
- if (secs < 1) {
96
- error_report("invalid physical secs number");
97
- goto fail;
98
- }
99
- }
100
-
101
- translation = BIOS_ATA_TRANSLATION_AUTO;
102
- value = qemu_opt_get(legacy_opts, "trans");
103
- if (value != NULL) {
104
- if (!cyls) {
105
- error_report("'%s' trans must be used with cyls, heads and secs",
106
- value);
107
- goto fail;
108
- }
109
- if (!strcmp(value, "none")) {
110
- translation = BIOS_ATA_TRANSLATION_NONE;
111
- } else if (!strcmp(value, "lba")) {
112
- translation = BIOS_ATA_TRANSLATION_LBA;
113
- } else if (!strcmp(value, "large")) {
114
- translation = BIOS_ATA_TRANSLATION_LARGE;
115
- } else if (!strcmp(value, "rechs")) {
116
- translation = BIOS_ATA_TRANSLATION_RECHS;
117
- } else if (!strcmp(value, "auto")) {
118
- translation = BIOS_ATA_TRANSLATION_AUTO;
119
- } else {
120
- error_report("'%s' invalid translation type", value);
121
- goto fail;
122
- }
123
- }
124
-
125
- if (media == MEDIA_CDROM) {
126
- if (cyls || secs || heads) {
127
- error_report("CHS can't be set with media=cdrom");
128
- goto fail;
129
- }
130
- }
131
-
132
/* Device address specified by bus/unit or index.
133
* If none was specified, try to find the first free one. */
134
bus_id = qemu_opt_get_number(legacy_opts, "bus", 0);
135
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
136
dinfo = g_malloc0(sizeof(*dinfo));
137
dinfo->opts = all_opts;
138
139
- dinfo->cyls = cyls;
140
- dinfo->heads = heads;
141
- dinfo->secs = secs;
142
- dinfo->trans = translation;
143
-
144
dinfo->type = type;
145
dinfo->bus = bus_id;
146
dinfo->unit = unit_id;
147
diff --git a/hw/block/block.c b/hw/block/block.c
148
index XXXXXXX..XXXXXXX 100644
149
--- a/hw/block/block.c
150
+++ b/hw/block/block.c
151
@@ -XXX,XX +XXX,XX @@ bool blkconf_geometry(BlockConf *conf, int *ptrans,
152
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
153
Error **errp)
154
{
155
- DriveInfo *dinfo;
156
-
157
- if (!conf->cyls && !conf->heads && !conf->secs) {
158
- /* try to fall back to value set with legacy -drive cyls=... */
159
- dinfo = blk_legacy_dinfo(conf->blk);
160
- if (dinfo) {
161
- conf->cyls = dinfo->cyls;
162
- conf->heads = dinfo->heads;
163
- conf->secs = dinfo->secs;
164
- if (ptrans) {
165
- *ptrans = dinfo->trans;
166
- }
167
- }
168
- }
169
if (!conf->cyls && !conf->heads && !conf->secs) {
170
hd_geometry_guess(conf->blk,
171
&conf->cyls, &conf->heads, &conf->secs,
172
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
173
index XXXXXXX..XXXXXXX 100644
174
--- a/tests/hd-geo-test.c
175
+++ b/tests/hd-geo-test.c
176
@@ -XXX,XX +XXX,XX @@ static void setup_mbr(int img_idx, MBRcontents mbr)
177
178
static int setup_ide(int argc, char *argv[], int argv_sz,
179
int ide_idx, const char *dev, int img_idx,
180
- MBRcontents mbr, const char *opts)
181
+ MBRcontents mbr)
182
{
183
char *s1, *s2, *s3;
184
185
@@ -XXX,XX +XXX,XX @@ static int setup_ide(int argc, char *argv[], int argv_sz,
186
s3 = g_strdup(",media=cdrom");
187
}
188
argc = append_arg(argc, argv, argv_sz,
189
- g_strdup_printf("%s%s%s%s", s1, s2, s3, opts));
190
+ g_strdup_printf("%s%s%s", s1, s2, s3));
191
g_free(s1);
192
g_free(s2);
193
g_free(s3);
194
@@ -XXX,XX +XXX,XX @@ static void test_ide_mbr(bool use_device, MBRcontents mbr)
195
for (i = 0; i < backend_last; i++) {
196
cur_ide[i] = &hd_chst[i][mbr];
197
dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
198
- argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr, "");
199
+ argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
200
}
201
args = g_strjoinv(" ", argv);
202
qtest_start(args);
203
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_user(const char *dev, bool trans)
204
const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
205
206
argc = setup_common(argv, ARGV_SIZE);
207
- opts = g_strdup_printf("%s,%s%scyls=%d,heads=%d,secs=%d",
208
- dev ?: "",
209
- trans && dev ? "bios-chs-" : "",
210
- trans ? "trans=lba," : "",
211
+ opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
212
+ dev, trans ? "bios-chs-trans=lba," : "",
213
expected_chst.cyls, expected_chst.heads,
214
expected_chst.secs);
215
cur_ide[0] = &expected_chst;
216
- argc = setup_ide(argc, argv, ARGV_SIZE,
217
- 0, dev ? opts : NULL, backend_small, mbr_chs,
218
- dev ? "" : opts);
219
+ argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
220
g_free(opts);
221
args = g_strjoinv(" ", argv);
222
qtest_start(args);
223
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_user(const char *dev, bool trans)
224
}
225
226
/*
227
- * Test case: IDE device (if=ide) with explicit CHS
228
- */
229
-static void test_ide_drive_user_chs(void)
230
-{
231
- test_ide_drive_user(NULL, false);
232
-}
233
-
234
-/*
235
- * Test case: IDE device (if=ide) with explicit CHS and translation
236
- */
237
-static void test_ide_drive_user_chst(void)
238
-{
239
- test_ide_drive_user(NULL, true);
240
-}
241
-
242
-/*
243
* Test case: IDE device (if=none) with explicit CHS
244
*/
245
static void test_ide_device_user_chs(void)
246
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_cd_0(void)
247
for (i = 0; i <= backend_empty; i++) {
248
ide_idx = backend_empty - i;
249
cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
250
- argc = setup_ide(argc, argv, ARGV_SIZE,
251
- ide_idx, NULL, i, mbr_blank, "");
252
+ argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
253
}
254
args = g_strjoinv(" ", argv);
255
qtest_start(args);
256
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
257
qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
258
qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
259
qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
260
- qtest_add_func("hd-geo/ide/drive/user/chs", test_ide_drive_user_chs);
261
- qtest_add_func("hd-geo/ide/drive/user/chst", test_ide_drive_user_chst);
262
qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
263
qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
264
qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
265
diff --git a/hmp-commands.hx b/hmp-commands.hx
266
index XXXXXXX..XXXXXXX 100644
267
--- a/hmp-commands.hx
268
+++ b/hmp-commands.hx
269
@@ -XXX,XX +XXX,XX @@ ETEXI
270
.params = "[-n] [[<domain>:]<bus>:]<slot>\n"
271
"[file=file][,if=type][,bus=n]\n"
272
"[,unit=m][,media=d][,index=i]\n"
273
- "[,cyls=c,heads=h,secs=s[,trans=t]]\n"
274
"[,snapshot=on|off][,cache=on|off]\n"
275
"[,readonly=on|off][,copy-on-read=on|off]",
276
.help = "add drive to PCI storage controller",
277
diff --git a/qemu-doc.texi b/qemu-doc.texi
278
index XXXXXXX..XXXXXXX 100644
279
--- a/qemu-doc.texi
280
+++ b/qemu-doc.texi
281
@@ -XXX,XX +XXX,XX @@ with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
282
(for embedded NICs). The new syntax allows different settings to be
283
provided per NIC.
284
285
-@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
286
-
287
-The drive geometry arguments are replaced by the the geometry arguments
288
-that can be specified with the ``-device'' parameter.
289
-
290
@subsection -drive serial=... (since 2.10.0)
291
292
The drive serial argument is replaced by the the serial argument
293
diff --git a/qemu-options.hx b/qemu-options.hx
294
index XXXXXXX..XXXXXXX 100644
295
--- a/qemu-options.hx
296
+++ b/qemu-options.hx
297
@@ -XXX,XX +XXX,XX @@ ETEXI
298
299
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
300
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
301
- " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
302
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
303
- " [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
304
+ " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
305
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
306
" [,readonly=on|off][,copy-on-read=on|off]\n"
307
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
308
@@ -XXX,XX +XXX,XX @@ This option defines where is connected the drive by using an index in the list
309
of available connectors of a given interface type.
310
@item media=@var{media}
311
This option defines the type of the media: disk or cdrom.
312
-@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
313
-Force disk physical geometry and the optional BIOS translation (trans=none or
314
-lba). These parameters are deprecated, use the corresponding parameters
315
-of @code{-device} instead.
316
@item snapshot=@var{snapshot}
317
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
318
(see @option{-snapshot}).
319
--
320
2.13.6
321
322
diff view generated by jsdifflib
1
This is a function that doesn't do any option parsing, but just does
1
The -drive option addr was deprecated in QEMU 2.10. It's time to remove
2
some basic BlockDriverState setup and calls the .bdrv_open() function of
2
it.
3
the block driver.
4
3
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
7
---
8
block.c | 112 +++++++++++++++++++++++++++++++++++++---------------------------
8
include/sysemu/blockdev.h | 1 -
9
1 file changed, 65 insertions(+), 47 deletions(-)
9
blockdev.c | 17 +----------------
10
device-hotplug.c | 4 ----
11
qemu-doc.texi | 5 -----
12
qemu-options.hx | 5 +----
13
5 files changed, 2 insertions(+), 30 deletions(-)
10
14
11
diff --git a/block.c b/block.c
15
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
17
--- a/include/sysemu/blockdev.h
14
+++ b/block.c
18
+++ b/include/sysemu/blockdev.h
15
@@ -XXX,XX +XXX,XX @@ out:
19
@@ -XXX,XX +XXX,XX @@ typedef enum {
16
g_free(gen_node_name);
20
} BlockInterfaceType;
17
}
21
18
22
struct DriveInfo {
19
+static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
23
- const char *devaddr;
20
+ const char *node_name, QDict *options,
24
BlockInterfaceType type;
21
+ int open_flags, Error **errp)
25
int bus;
22
+{
26
int unit;
23
+ Error *local_err = NULL;
27
diff --git a/blockdev.c b/blockdev.c
24
+ int ret;
28
index XXXXXXX..XXXXXXX 100644
25
+
29
--- a/blockdev.c
26
+ bdrv_assign_node_name(bs, node_name, &local_err);
30
+++ b/blockdev.c
27
+ if (local_err) {
31
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
28
+ error_propagate(errp, local_err);
32
.type = QEMU_OPT_STRING,
29
+ return -EINVAL;
33
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
30
+ }
34
},{
31
+
35
- .name = "addr",
32
+ bs->drv = drv;
36
- .type = QEMU_OPT_STRING,
33
+ bs->opaque = g_malloc0(drv->instance_size);
37
- .help = "pci address (virtio only)",
34
+
38
- },{
35
+ if (drv->bdrv_file_open) {
39
.name = "serial",
36
+ assert(!drv->bdrv_needs_filename || bs->filename[0]);
40
.type = QEMU_OPT_STRING,
37
+ ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
41
.help = "disk serial number",
38
+ } else {
42
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
39
+ ret = drv->bdrv_open(bs, options, open_flags, &local_err);
43
DriveMediaType media = MEDIA_DISK;
40
+ }
44
BlockInterfaceType type;
41
+
45
int max_devs, bus_id, unit_id, index;
42
+ if (ret < 0) {
46
- const char *devaddr;
43
+ if (local_err) {
47
const char *werror, *rerror;
44
+ error_propagate(errp, local_err);
48
bool read_only = false;
45
+ } else if (bs->filename[0]) {
49
bool copy_on_read;
46
+ error_setg_errno(errp, -ret, "Could not open '%s'", bs->filename);
50
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
47
+ } else {
51
Error *local_err = NULL;
48
+ error_setg_errno(errp, -ret, "Could not open image");
52
int i;
49
+ }
53
const char *deprecated[] = {
50
+ goto free_and_fail;
54
- "serial", "addr"
51
+ }
55
+ "serial"
52
+
56
};
53
+ ret = refresh_total_sectors(bs, bs->total_sectors);
57
54
+ if (ret < 0) {
58
/* Change legacy command line options into QMP ones */
55
+ error_setg_errno(errp, -ret, "Could not refresh total sector count");
59
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
56
+ goto free_and_fail;
60
}
57
+ }
61
58
+
62
/* Add virtio block device */
59
+ bdrv_refresh_limits(bs, &local_err);
63
- devaddr = qemu_opt_get(legacy_opts, "addr");
60
+ if (local_err) {
64
- if (devaddr && type != IF_VIRTIO) {
61
+ error_propagate(errp, local_err);
65
- error_report("addr is not supported by this bus type");
62
+ ret = -EINVAL;
66
- goto fail;
63
+ goto free_and_fail;
64
+ }
65
+
66
+ assert(bdrv_opt_mem_align(bs) != 0);
67
+ assert(bdrv_min_mem_align(bs) != 0);
68
+ assert(is_power_of_2(bs->bl.request_alignment));
69
+
70
+ return 0;
71
+
72
+free_and_fail:
73
+ /* FIXME Close bs first if already opened*/
74
+ g_free(bs->opaque);
75
+ bs->opaque = NULL;
76
+ bs->drv = NULL;
77
+ return ret;
78
+}
79
+
80
QemuOptsList bdrv_runtime_opts = {
81
.name = "bdrv_common",
82
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
83
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
84
trace_bdrv_open_common(bs, filename ?: "", bs->open_flags,
85
drv->format_name);
86
87
- node_name = qemu_opt_get(opts, "node-name");
88
- bdrv_assign_node_name(bs, node_name, &local_err);
89
- if (local_err) {
90
- error_propagate(errp, local_err);
91
- ret = -EINVAL;
92
- goto fail_opts;
93
- }
67
- }
94
-
68
-
95
bs->read_only = !(bs->open_flags & BDRV_O_RDWR);
69
if (type == IF_VIRTIO) {
96
70
QemuOpts *devopts;
97
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
71
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
98
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
72
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
73
}
74
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
75
&error_abort);
76
- if (devaddr) {
77
- qemu_opt_set(devopts, "addr", devaddr, &error_abort);
78
- }
99
}
79
}
100
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), bs->filename);
80
101
81
filename = qemu_opt_get(legacy_opts, "file");
102
- bs->drv = drv;
82
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
103
- bs->opaque = g_malloc0(drv->instance_size);
83
dinfo->type = type;
84
dinfo->bus = bus_id;
85
dinfo->unit = unit_id;
86
- dinfo->devaddr = devaddr;
87
dinfo->serial = g_strdup(serial);
88
89
blk_set_legacy_dinfo(blk, dinfo);
90
diff --git a/device-hotplug.c b/device-hotplug.c
91
index XXXXXXX..XXXXXXX 100644
92
--- a/device-hotplug.c
93
+++ b/device-hotplug.c
94
@@ -XXX,XX +XXX,XX @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
95
if (!dinfo) {
96
goto err;
97
}
98
- if (dinfo->devaddr) {
99
- monitor_printf(mon, "Parameter addr not supported\n");
100
- goto err;
101
- }
102
103
switch (dinfo->type) {
104
case IF_NONE:
105
diff --git a/qemu-doc.texi b/qemu-doc.texi
106
index XXXXXXX..XXXXXXX 100644
107
--- a/qemu-doc.texi
108
+++ b/qemu-doc.texi
109
@@ -XXX,XX +XXX,XX @@ provided per NIC.
110
The drive serial argument is replaced by the the serial argument
111
that can be specified with the ``-device'' parameter.
112
113
-@subsection -drive addr=... (since 2.10.0)
104
-
114
-
105
/* Open the image, either directly or using a protocol */
115
-The drive addr argument is replaced by the the addr argument
106
open_flags = bdrv_open_flags(bs, bs->open_flags);
116
-that can be specified with the ``-device'' parameter.
107
- if (drv->bdrv_file_open) {
108
- assert(file == NULL);
109
- assert(!drv->bdrv_needs_filename || filename != NULL);
110
- ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
111
- } else {
112
- ret = drv->bdrv_open(bs, options, open_flags, &local_err);
113
- }
114
-
117
-
115
- if (ret < 0) {
118
@subsection -usbdevice (since 2.10.0)
116
- if (local_err) {
119
117
- error_propagate(errp, local_err);
120
The ``-usbdevice DEV'' argument is now a synonym for setting
118
- } else if (bs->filename[0]) {
121
diff --git a/qemu-options.hx b/qemu-options.hx
119
- error_setg_errno(errp, -ret, "Could not open '%s'", bs->filename);
122
index XXXXXXX..XXXXXXX 100644
120
- } else {
123
--- a/qemu-options.hx
121
- error_setg_errno(errp, -ret, "Could not open image");
124
+++ b/qemu-options.hx
122
- }
125
@@ -XXX,XX +XXX,XX @@ ETEXI
123
- goto free_and_fail;
126
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
124
- }
127
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
125
+ node_name = qemu_opt_get(opts, "node-name");
128
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
126
129
- " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
127
- ret = refresh_total_sectors(bs, bs->total_sectors);
130
+ " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
128
+ assert(!drv->bdrv_file_open || file == NULL);
131
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
129
+ ret = bdrv_open_driver(bs, drv, node_name, options, open_flags, errp);
132
" [,readonly=on|off][,copy-on-read=on|off]\n"
130
if (ret < 0) {
133
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
131
- error_setg_errno(errp, -ret, "Could not refresh total sector count");
134
@@ -XXX,XX +XXX,XX @@ an untrusted format header.
132
- goto free_and_fail;
135
This option specifies the serial number to assign to the device. This
133
- }
136
parameter is deprecated, use the corresponding parameter of @code{-device}
134
-
137
instead.
135
- bdrv_refresh_limits(bs, &local_err);
138
-@item addr=@var{addr}
136
- if (local_err) {
139
-Specify the controller's PCI address (if=virtio only). This parameter is
137
- error_propagate(errp, local_err);
140
-deprecated, use the corresponding parameter of @code{-device} instead.
138
- ret = -EINVAL;
141
@item werror=@var{action},rerror=@var{action}
139
- goto free_and_fail;
142
Specify which @var{action} to take on write and read errors. Valid actions are:
140
+ goto fail_opts;
143
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
141
}
142
143
- assert(bdrv_opt_mem_align(bs) != 0);
144
- assert(bdrv_min_mem_align(bs) != 0);
145
- assert(is_power_of_2(bs->bl.request_alignment));
146
-
147
qemu_opts_del(opts);
148
return 0;
149
150
-free_and_fail:
151
- g_free(bs->opaque);
152
- bs->opaque = NULL;
153
- bs->drv = NULL;
154
fail_opts:
155
qemu_opts_del(opts);
156
return ret;
157
--
144
--
158
1.8.3.1
145
2.13.6
159
146
160
147
diff view generated by jsdifflib
New patch
1
1
The -drive option serial was deprecated in QEMU 2.10. It's time to
2
remove it.
3
4
Tests need to be updated to set the serial number with -global instead
5
of using the -drive option.
6
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Markus Armbruster <armbru@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
---
11
include/hw/block/block.h | 1 -
12
include/sysemu/blockdev.h | 1 -
13
block/block-backend.c | 1 -
14
blockdev.c | 10 ----------
15
hw/block/block.c | 13 -------------
16
hw/block/nvme.c | 1 -
17
hw/block/virtio-blk.c | 1 -
18
hw/ide/qdev.c | 1 -
19
hw/scsi/scsi-disk.c | 1 -
20
hw/usb/dev-storage.c | 1 -
21
tests/ahci-test.c | 6 +++---
22
tests/ide-test.c | 8 ++++----
23
qemu-doc.texi | 5 -----
24
qemu-options.hx | 6 +-----
25
14 files changed, 8 insertions(+), 48 deletions(-)
26
27
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/include/hw/block/block.h
30
+++ b/include/hw/block/block.h
31
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
32
33
/* Configuration helpers */
34
35
-void blkconf_serial(BlockConf *conf, char **serial);
36
bool blkconf_geometry(BlockConf *conf, int *trans,
37
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
38
Error **errp);
39
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/include/sysemu/blockdev.h
42
+++ b/include/sysemu/blockdev.h
43
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
44
bool is_default; /* Added by default_drive() ? */
45
int media_cd;
46
QemuOpts *opts;
47
- char *serial;
48
QTAILQ_ENTRY(DriveInfo) next;
49
};
50
51
diff --git a/block/block-backend.c b/block/block-backend.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/block/block-backend.c
54
+++ b/block/block-backend.c
55
@@ -XXX,XX +XXX,XX @@ static void drive_info_del(DriveInfo *dinfo)
56
return;
57
}
58
qemu_opts_del(dinfo->opts);
59
- g_free(dinfo->serial);
60
g_free(dinfo);
61
}
62
63
diff --git a/blockdev.c b/blockdev.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/blockdev.c
66
+++ b/blockdev.c
67
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
68
.type = QEMU_OPT_STRING,
69
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
70
},{
71
- .name = "serial",
72
- .type = QEMU_OPT_STRING,
73
- .help = "disk serial number",
74
- },{
75
.name = "file",
76
.type = QEMU_OPT_STRING,
77
.help = "file name",
78
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
79
const char *werror, *rerror;
80
bool read_only = false;
81
bool copy_on_read;
82
- const char *serial;
83
const char *filename;
84
Error *local_err = NULL;
85
int i;
86
const char *deprecated[] = {
87
- "serial"
88
};
89
90
/* Change legacy command line options into QMP ones */
91
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
92
goto fail;
93
}
94
95
- /* Serial number */
96
- serial = qemu_opt_get(legacy_opts, "serial");
97
-
98
/* no id supplied -> create one */
99
if (qemu_opts_id(all_opts) == NULL) {
100
char *new_id;
101
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
102
dinfo->type = type;
103
dinfo->bus = bus_id;
104
dinfo->unit = unit_id;
105
- dinfo->serial = g_strdup(serial);
106
107
blk_set_legacy_dinfo(blk, dinfo);
108
109
diff --git a/hw/block/block.c b/hw/block/block.c
110
index XXXXXXX..XXXXXXX 100644
111
--- a/hw/block/block.c
112
+++ b/hw/block/block.c
113
@@ -XXX,XX +XXX,XX @@
114
#include "qapi/qapi-types-block.h"
115
#include "qemu/error-report.h"
116
117
-void blkconf_serial(BlockConf *conf, char **serial)
118
-{
119
- DriveInfo *dinfo;
120
-
121
- if (!*serial) {
122
- /* try to fall back to value set with legacy -drive serial=... */
123
- dinfo = blk_legacy_dinfo(conf->blk);
124
- if (dinfo) {
125
- *serial = g_strdup(dinfo->serial);
126
- }
127
- }
128
-}
129
-
130
void blkconf_blocksizes(BlockConf *conf)
131
{
132
BlockBackend *blk = conf->blk;
133
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/hw/block/nvme.c
136
+++ b/hw/block/nvme.c
137
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
138
return;
139
}
140
141
- blkconf_serial(&n->conf, &n->serial);
142
if (!n->serial) {
143
error_setg(errp, "serial property not set");
144
return;
145
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/hw/block/virtio-blk.c
148
+++ b/hw/block/virtio-blk.c
149
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
150
return;
151
}
152
153
- blkconf_serial(&conf->conf, &conf->serial);
154
if (!blkconf_apply_backend_options(&conf->conf,
155
blk_is_read_only(conf->conf.blk), true,
156
errp)) {
157
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
158
index XXXXXXX..XXXXXXX 100644
159
--- a/hw/ide/qdev.c
160
+++ b/hw/ide/qdev.c
161
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
162
return;
163
}
164
165
- blkconf_serial(&dev->conf, &dev->serial);
166
if (kind != IDE_CD) {
167
if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
168
errp)) {
169
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
170
index XXXXXXX..XXXXXXX 100644
171
--- a/hw/scsi/scsi-disk.c
172
+++ b/hw/scsi/scsi-disk.c
173
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
174
return;
175
}
176
177
- blkconf_serial(&s->qdev.conf, &s->serial);
178
blkconf_blocksizes(&s->qdev.conf);
179
180
if (s->qdev.conf.logical_block_size >
181
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
182
index XXXXXXX..XXXXXXX 100644
183
--- a/hw/usb/dev-storage.c
184
+++ b/hw/usb/dev-storage.c
185
@@ -XXX,XX +XXX,XX @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
186
return;
187
}
188
189
- blkconf_serial(&s->conf, &dev->serial);
190
blkconf_blocksizes(&s->conf);
191
if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
192
errp)) {
193
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
194
index XXXXXXX..XXXXXXX 100644
195
--- a/tests/ahci-test.c
196
+++ b/tests/ahci-test.c
197
@@ -XXX,XX +XXX,XX @@ static AHCIQState *ahci_boot(const char *cli, ...)
198
s = ahci_vboot(cli, ap);
199
va_end(ap);
200
} else {
201
- cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s"
202
- ",format=%s"
203
+ cli = "-drive if=none,id=drive0,file=%s,cache=writeback,format=%s"
204
" -M q35 "
205
"-device ide-hd,drive=drive0 "
206
+ "-global ide-hd.serial=%s "
207
"-global ide-hd.ver=%s";
208
- s = ahci_boot(cli, tmp_path, "testdisk", imgfmt, "version");
209
+ s = ahci_boot(cli, tmp_path, imgfmt, "testdisk", "version");
210
}
211
212
return s;
213
diff --git a/tests/ide-test.c b/tests/ide-test.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/tests/ide-test.c
216
+++ b/tests/ide-test.c
217
@@ -XXX,XX +XXX,XX @@ static void test_bmdma_no_busmaster(void)
218
static void test_bmdma_setup(void)
219
{
220
ide_test_start(
221
- "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
222
- "-global ide-hd.ver=%s",
223
+ "-drive file=%s,if=ide,cache=writeback,format=raw "
224
+ "-global ide-hd.serial=%s -global ide-hd.ver=%s",
225
tmp_path, "testdisk", "version");
226
qtest_irq_intercept_in(global_qtest, "ioapic");
227
}
228
@@ -XXX,XX +XXX,XX @@ static void test_identify(void)
229
int ret;
230
231
ide_test_start(
232
- "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
233
- "-global ide-hd.ver=%s",
234
+ "-drive file=%s,if=ide,cache=writeback,format=raw "
235
+ "-global ide-hd.serial=%s -global ide-hd.ver=%s",
236
tmp_path, "testdisk", "version");
237
238
dev = get_pci_device(&bmdma_bar, &ide_bar);
239
diff --git a/qemu-doc.texi b/qemu-doc.texi
240
index XXXXXXX..XXXXXXX 100644
241
--- a/qemu-doc.texi
242
+++ b/qemu-doc.texi
243
@@ -XXX,XX +XXX,XX @@ with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
244
(for embedded NICs). The new syntax allows different settings to be
245
provided per NIC.
246
247
-@subsection -drive serial=... (since 2.10.0)
248
-
249
-The drive serial argument is replaced by the the serial argument
250
-that can be specified with the ``-device'' parameter.
251
-
252
@subsection -usbdevice (since 2.10.0)
253
254
The ``-usbdevice DEV'' argument is now a synonym for setting
255
diff --git a/qemu-options.hx b/qemu-options.hx
256
index XXXXXXX..XXXXXXX 100644
257
--- a/qemu-options.hx
258
+++ b/qemu-options.hx
259
@@ -XXX,XX +XXX,XX @@ ETEXI
260
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
261
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
262
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
263
- " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
264
+ " [,snapshot=on|off][,rerror=ignore|stop|report]\n"
265
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
266
" [,readonly=on|off][,copy-on-read=on|off]\n"
267
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
268
@@ -XXX,XX +XXX,XX @@ The default mode is @option{cache=writeback}.
269
Specify which disk @var{format} will be used rather than detecting
270
the format. Can be used to specify format=raw to avoid interpreting
271
an untrusted format header.
272
-@item serial=@var{serial}
273
-This option specifies the serial number to assign to the device. This
274
-parameter is deprecated, use the corresponding parameter of @code{-device}
275
-instead.
276
@item werror=@var{action},rerror=@var{action}
277
Specify which @var{action} to take on write and read errors. Valid actions are:
278
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
279
--
280
2.13.6
281
282
diff view generated by jsdifflib
1
In order to be able to do permission checking and to keep working with
1
We removed all options from the 'deprecated' array, so the code is dead
2
the BdrvChild based bdrv_truncate() that this involves, we need to
2
and can be removed as well.
3
create a temporary BlockBackend to resize the image.
4
3
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
7
---
6
---
8
blockdev.c | 7 ++++++-
7
blockdev.c | 12 ------------
9
1 file changed, 6 insertions(+), 1 deletion(-)
8
1 file changed, 12 deletions(-)
10
9
11
diff --git a/blockdev.c b/blockdev.c
10
diff --git a/blockdev.c b/blockdev.c
12
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
13
--- a/blockdev.c
12
--- a/blockdev.c
14
+++ b/blockdev.c
13
+++ b/blockdev.c
15
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
14
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
16
int64_t size, Error **errp)
15
const char *filename;
17
{
18
Error *local_err = NULL;
16
Error *local_err = NULL;
19
+ BlockBackend *blk = NULL;
17
int i;
20
BlockDriverState *bs;
18
- const char *deprecated[] = {
21
AioContext *aio_context;
19
- };
22
int ret;
20
23
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
21
/* Change legacy command line options into QMP ones */
24
goto out;
22
static const struct {
23
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
24
goto fail;
25
}
25
}
26
26
27
+ blk = blk_new();
27
- /* Other deprecated options */
28
+ blk_insert_bs(blk, bs);
28
- if (!qtest_enabled()) {
29
+
29
- for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
30
/* complete all in-flight operations before resizing the device */
30
- if (qemu_opt_get(legacy_opts, deprecated[i]) != NULL) {
31
bdrv_drain_all();
31
- error_report("'%s' is deprecated, please use the corresponding "
32
32
- "option of '-device' instead", deprecated[i]);
33
- ret = bdrv_truncate(bs, size);
33
- }
34
+ ret = blk_truncate(blk, size);
34
- }
35
switch (ret) {
35
- }
36
case 0:
36
-
37
break;
37
/* Media type */
38
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
38
value = qemu_opt_get(legacy_opts, "media");
39
}
39
if (value) {
40
41
out:
42
+ blk_unref(blk);
43
aio_context_release(aio_context);
44
}
45
46
--
40
--
47
1.8.3.1
41
2.13.6
48
42
49
43
diff view generated by jsdifflib