1
The following changes since commit 91fe7a376ad46e3cc5e82d418aad22173c948a3c:
1
The following changes since commit 931892e8a691a8a4151cc5fe1e13c14294bb28fb:
2
2
3
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging (2018-06-15 11:41:44 +0100)
3
Merge remote-tracking branch 'remotes/rth/tags/pull-s390-20170623' into staging (2017-06-23 18:11:48 +0100)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
9
9
for you to fetch changes up to 6266e900b8083945cb766b45c124fb3c42932cb3:
10
for you to fetch changes up to 704e41ba789ad88158f051eee648d7087beffac7:
10
11
11
block: Remove dead deprecation warning code (2018-06-15 14:49:44 +0200)
12
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-06-26' into queue-block (2017-06-26 14:57:27 +0200)
13
14
v2:
15
- Dropped "virtio-pci: use ioeventfd even when KVM is disabled"
12
16
13
----------------------------------------------------------------
17
----------------------------------------------------------------
14
Block layer patches:
15
18
16
- Fix options that work only with -drive or -blockdev, but not with
19
Block layer patches
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
23
20
24
----------------------------------------------------------------
21
----------------------------------------------------------------
25
Eric Blake (2):
22
Alberto Garcia (9):
26
qemu-img: Fix assert when mapping unaligned raw file
23
throttle: Update throttle-groups.c documentation
27
iotests: Add test 221 to catch qemu-img map regression
24
qcow2: Remove unused Error variable in do_perform_cow()
25
qcow2: Use unsigned int for both members of Qcow2COWRegion
26
qcow2: Make perform_cow() call do_perform_cow() twice
27
qcow2: Split do_perform_cow() into _read(), _encrypt() and _write()
28
qcow2: Allow reading both COW regions with only one request
29
qcow2: Pass a QEMUIOVector to do_perform_cow_{read,write}()
30
qcow2: Merge the writing of the COW regions with the guest data
31
qcow2: Use offset_into_cluster() and offset_to_l2_index()
28
32
29
John Snow (2):
33
Kevin Wolf (37):
30
jobs: fix stale wording
34
commit: Fix completion with extra reference
31
jobs: fix verb references in docs
35
qemu-iotests: Allow starting new qemu after cleanup
36
qemu-iotests: Test exiting qemu with running job
37
doc: Document generic -blockdev options
38
doc: Document driver-specific -blockdev options
39
qed: Use bottom half to resume waiting requests
40
qed: Make qed_read_table() synchronous
41
qed: Remove callback from qed_read_table()
42
qed: Remove callback from qed_read_l2_table()
43
qed: Remove callback from qed_find_cluster()
44
qed: Make qed_read_backing_file() synchronous
45
qed: Make qed_copy_from_backing_file() synchronous
46
qed: Remove callback from qed_copy_from_backing_file()
47
qed: Make qed_write_header() synchronous
48
qed: Remove callback from qed_write_header()
49
qed: Make qed_write_table() synchronous
50
qed: Remove GenericCB
51
qed: Remove callback from qed_write_table()
52
qed: Make qed_aio_read_data() synchronous
53
qed: Make qed_aio_write_main() synchronous
54
qed: Inline qed_commit_l2_update()
55
qed: Add return value to qed_aio_write_l1_update()
56
qed: Add return value to qed_aio_write_l2_update()
57
qed: Add return value to qed_aio_write_main()
58
qed: Add return value to qed_aio_write_cow()
59
qed: Add return value to qed_aio_write_inplace/alloc()
60
qed: Add return value to qed_aio_read/write_data()
61
qed: Remove ret argument from qed_aio_next_io()
62
qed: Remove recursion in qed_aio_next_io()
63
qed: Implement .bdrv_co_readv/writev
64
qed: Use CoQueue for serialising allocations
65
qed: Simplify request handling
66
qed: Use a coroutine for need_check_timer
67
qed: Add coroutine_fn to I/O path functions
68
qed: Use bdrv_co_* for coroutine_fns
69
block: Remove bdrv_aio_readv/writev/flush()
70
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-06-26' into queue-block
32
71
33
Kevin Wolf (4):
72
Manos Pitsidianakis (1):
34
block: Remove deprecated -drive geometry options
73
block: change variable names in BlockDriverState
35
block: Remove deprecated -drive option addr
36
block: Remove deprecated -drive option serial
37
block: Remove dead deprecation warning code
38
74
39
Markus Armbruster (17):
75
Max Reitz (3):
40
rbd: Drop deprecated -drive parameter "filename"
76
blkdebug: Catch bs->exact_filename overflow
41
iscsi: Drop deprecated -drive parameter "filename"
77
blkverify: Catch bs->exact_filename overflow
42
qobject: Move block-specific qdict code to block-qdict.c
78
block: Do not strcmp() with NULL uri->scheme
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
57
79
58
Max Reitz (1):
80
Stefan Hajnoczi (9):
59
block: Add block-specific QDict header
81
block: count bdrv_co_rw_vmstate() requests
82
block: use BDRV_POLL_WHILE() in bdrv_rw_vmstate()
83
migration: avoid recursive AioContext locking in save_vmstate()
84
migration: use bdrv_drain_all_begin/end() instead bdrv_drain_all()
85
migration: hold AioContext lock for loadvm qemu_fclose()
86
qemu-iotests: 068: extract _qemu() function
87
qemu-iotests: 068: use -drive/-device instead of -hda
88
qemu-iotests: 068: test iothread mode
89
qemu-img: don't shadow opts variable in img_dd()
60
90
61
qapi/block-core.json | 19 ++
91
Stephen Bates (1):
62
qapi/job.json | 23 +-
92
nvme: Add support for Read Data and Write Data in CMBs.
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
93
94
sochin.jiang (1):
95
fix: avoid an infinite loop or a dangling pointer problem in img_commit
96
97
block/Makefile.objs | 2 +-
98
block/blkdebug.c | 46 +--
99
block/blkreplay.c | 8 +-
100
block/blkverify.c | 12 +-
101
block/block-backend.c | 22 +-
102
block/commit.c | 7 +
103
block/file-posix.c | 34 +-
104
block/io.c | 240 ++-----------
105
block/iscsi.c | 20 +-
106
block/mirror.c | 8 +-
107
block/nbd-client.c | 8 +-
108
block/nbd-client.h | 4 +-
109
block/nbd.c | 6 +-
110
block/nfs.c | 2 +-
111
block/qcow2-cluster.c | 201 ++++++++---
112
block/qcow2.c | 94 +++--
113
block/qcow2.h | 11 +-
114
block/qed-cluster.c | 124 +++----
115
block/qed-gencb.c | 33 --
116
block/qed-table.c | 261 +++++---------
117
block/qed.c | 779 ++++++++++++++++-------------------------
118
block/qed.h | 54 +--
119
block/raw-format.c | 8 +-
120
block/rbd.c | 4 +-
121
block/sheepdog.c | 12 +-
122
block/ssh.c | 2 +-
123
block/throttle-groups.c | 2 +-
124
block/trace-events | 3 -
125
blockjob.c | 4 +-
126
hw/block/nvme.c | 83 +++--
127
hw/block/nvme.h | 1 +
128
include/block/block.h | 16 +-
129
include/block/block_int.h | 6 +-
130
include/block/blockjob.h | 18 +
131
include/sysemu/block-backend.h | 20 +-
132
migration/savevm.c | 32 +-
133
qemu-img.c | 29 +-
134
qemu-io-cmds.c | 46 +--
135
qemu-options.hx | 221 ++++++++++--
136
tests/qemu-iotests/068 | 37 +-
137
tests/qemu-iotests/068.out | 11 +-
138
tests/qemu-iotests/185 | 206 +++++++++++
139
tests/qemu-iotests/185.out | 59 ++++
140
tests/qemu-iotests/common.qemu | 3 +
141
tests/qemu-iotests/group | 1 +
142
45 files changed, 1476 insertions(+), 1324 deletions(-)
143
delete mode 100644 block/qed-gencb.c
144
create mode 100755 tests/qemu-iotests/185
145
create mode 100644 tests/qemu-iotests/185.out
146
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
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
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
Although qemu-img creates aligned files (by rounding up), it
4
must also gracefully handle files that are not sector-aligned.
5
Test that the bug fixed in the previous patch does not recur.
6
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>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
tests/qemu-iotests/221 | 60 ++++++++++++++++++++++++++++++++++++++++++++++
17
tests/qemu-iotests/221.out | 16 +++++++++++++
18
tests/qemu-iotests/group | 1 +
19
3 files changed, 77 insertions(+)
20
create mode 100755 tests/qemu-iotests/221
21
create mode 100644 tests/qemu-iotests/221.out
22
23
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
24
new file mode 100755
25
index XXXXXXX..XXXXXXX
26
--- /dev/null
27
+++ b/tests/qemu-iotests/221
28
@@ -XXX,XX +XXX,XX @@
29
+#!/bin/bash
30
+#
31
+# Test qemu-img vs. unaligned images
32
+#
33
+# Copyright (C) 2018 Red Hat, Inc.
34
+#
35
+# This program is free software; you can redistribute it and/or modify
36
+# it under the terms of the GNU General Public License as published by
37
+# the Free Software Foundation; either version 2 of the License, or
38
+# (at your option) any later version.
39
+#
40
+# This program is distributed in the hope that it will be useful,
41
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
42
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43
+# GNU General Public License for more details.
44
+#
45
+# You should have received a copy of the GNU General Public License
46
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
47
+#
48
+
49
+seq="$(basename $0)"
50
+echo "QA output created by $seq"
51
+
52
+here="$PWD"
53
+status=1 # failure is the default!
54
+
55
+_cleanup()
56
+{
57
+ _cleanup_test_img
58
+}
59
+trap "_cleanup; exit \$status" 0 1 2 3 15
60
+
61
+# get standard environment, filters and checks
62
+. ./common.rc
63
+. ./common.filter
64
+
65
+_supported_fmt raw
66
+_supported_proto file
67
+_supported_os Linux
68
+
69
+echo
70
+echo "=== Check mapping of unaligned raw image ==="
71
+echo
72
+
73
+_make_test_img 43009 # qemu-img create rounds size up
74
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
75
+
76
+truncate --size=43009 "$TEST_IMG" # so we resize it and check again
77
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
78
+
79
+$QEMU_IO -c 'w 43008 1' "$TEST_IMG" | _filter_qemu_io # writing also rounds up
80
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
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
84
+
85
+# success, all done
86
+echo '*** done'
87
+rm -f $seq.full
88
+status=0
89
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
90
new file mode 100644
91
index XXXXXXX..XXXXXXX
92
--- /dev/null
93
+++ b/tests/qemu-iotests/221.out
94
@@ -XXX,XX +XXX,XX @@
95
+QA output created by 221
96
+
97
+=== Check mapping of unaligned raw image ===
98
+
99
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=43009
100
+[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
101
+[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
102
+wrote 1/1 bytes at offset 43008
103
+1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
104
+[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
105
+{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
106
+{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
107
+[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
108
+{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
109
+{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
110
+*** done
111
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
112
index XXXXXXX..XXXXXXX 100644
113
--- a/tests/qemu-iotests/group
114
+++ b/tests/qemu-iotests/group
115
@@ -XXX,XX +XXX,XX @@
116
217 rw auto quick
117
218 rw auto quick
118
219 rw auto
119
+221 rw auto quick
120
--
121
2.13.6
122
123
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
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
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
These point to the job versions now, not the blockjob versions which
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.
8
9
Signed-off-by: John Snow <jsnow@redhat.com>
10
Reviewed-by: Jeff Cody <jcody@redhat.com>
11
Reviewed-by: Markus Armbruster <armbru@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
qapi/job.json | 12 ++++++------
15
1 file changed, 6 insertions(+), 6 deletions(-)
16
17
diff --git a/qapi/job.json b/qapi/job.json
18
index XXXXXXX..XXXXXXX 100644
19
--- a/qapi/job.json
20
+++ b/qapi/job.json
21
@@ -XXX,XX +XXX,XX @@
22
#
23
# Represents command verbs that can be applied to a job.
24
#
25
-# @cancel: see @block-job-cancel
26
+# @cancel: see @job-cancel
27
#
28
-# @pause: see @block-job-pause
29
+# @pause: see @job-pause
30
#
31
-# @resume: see @block-job-resume
32
+# @resume: see @job-resume
33
#
34
# @set-speed: see @block-job-set-speed
35
#
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
##
47
--
48
2.13.6
49
50
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
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
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
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>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
block/iscsi.c | 23 ++---------------------
11
1 file changed, 2 insertions(+), 21 deletions(-)
12
13
diff --git a/block/iscsi.c b/block/iscsi.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/iscsi.c
16
+++ b/block/iscsi.c
17
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
18
.name = "timeout",
19
.type = QEMU_OPT_NUMBER,
20
},
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:
62
+
63
return ret;
64
}
65
66
--
67
2.13.6
68
69
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
There are numerous QDict functions that have been introduced for and are
4
used only by the block layer. Move their declarations into an own
5
header file to reflect that.
6
7
While qdict_extract_subqdict() is in fact used outside of the block
8
layer (in util/qemu-config.c), it is still a function related very
9
closely to how the block layer works with nested QDicts, namely by
10
sometimes flattening them. Therefore, its declaration is put into this
11
header as well and util/qemu-config.c includes it with a comment stating
12
exactly which function it needs.
13
14
Suggested-by: Markus Armbruster <armbru@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Message-Id: <20180509165530.29561-7-mreitz@redhat.com>
17
[Copyright note tweaked, superfluous includes dropped]
18
Signed-off-by: Markus Armbruster <armbru@redhat.com>
19
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
22
include/block/qdict.h | 32 ++++++++++++++++++++++++++++++++
23
include/qapi/qmp/qdict.h | 17 -----------------
24
block.c | 1 +
25
block/gluster.c | 1 +
26
block/iscsi.c | 1 +
27
block/nbd.c | 1 +
28
block/nfs.c | 1 +
29
block/parallels.c | 1 +
30
block/qcow.c | 1 +
31
block/qcow2.c | 1 +
32
block/qed.c | 1 +
33
block/quorum.c | 1 +
34
block/rbd.c | 1 +
35
block/sheepdog.c | 1 +
36
block/snapshot.c | 1 +
37
block/ssh.c | 1 +
38
block/vhdx.c | 1 +
39
block/vpc.c | 1 +
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 */
117
diff --git a/block.c b/block.c
118
index XXXXXXX..XXXXXXX 100644
119
--- a/block.c
120
+++ b/block.c
121
@@ -XXX,XX +XXX,XX @@
122
#include "block/block_int.h"
123
#include "block/blockjob.h"
124
#include "block/nbd.h"
125
+#include "block/qdict.h"
126
#include "qemu/error-report.h"
127
#include "module_block.h"
128
#include "qemu/module.h"
129
diff --git a/block/gluster.c b/block/gluster.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/gluster.c
132
+++ b/block/gluster.c
133
@@ -XXX,XX +XXX,XX @@
134
#include "qemu/osdep.h"
135
#include <glusterfs/api/glfs.h>
136
#include "block/block_int.h"
137
+#include "block/qdict.h"
138
#include "qapi/error.h"
139
#include "qapi/qmp/qdict.h"
140
#include "qapi/qmp/qerror.h"
141
diff --git a/block/iscsi.c b/block/iscsi.c
142
index XXXXXXX..XXXXXXX 100644
143
--- a/block/iscsi.c
144
+++ b/block/iscsi.c
145
@@ -XXX,XX +XXX,XX @@
146
#include "qemu/bitops.h"
147
#include "qemu/bitmap.h"
148
#include "block/block_int.h"
149
+#include "block/qdict.h"
150
#include "scsi/constants.h"
151
#include "qemu/iov.h"
152
#include "qemu/option.h"
153
diff --git a/block/nbd.c b/block/nbd.c
154
index XXXXXXX..XXXXXXX 100644
155
--- a/block/nbd.c
156
+++ b/block/nbd.c
157
@@ -XXX,XX +XXX,XX @@
158
159
#include "qemu/osdep.h"
160
#include "nbd-client.h"
161
+#include "block/qdict.h"
162
#include "qapi/error.h"
163
#include "qemu/uri.h"
164
#include "block/block_int.h"
165
diff --git a/block/nfs.c b/block/nfs.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/block/nfs.c
168
+++ b/block/nfs.c
169
@@ -XXX,XX +XXX,XX @@
170
#include "qemu/error-report.h"
171
#include "qapi/error.h"
172
#include "block/block_int.h"
173
+#include "block/qdict.h"
174
#include "trace.h"
175
#include "qemu/iov.h"
176
#include "qemu/option.h"
177
diff --git a/block/parallels.c b/block/parallels.c
178
index XXXXXXX..XXXXXXX 100644
179
--- a/block/parallels.c
180
+++ b/block/parallels.c
181
@@ -XXX,XX +XXX,XX @@
182
#include "qemu/osdep.h"
183
#include "qapi/error.h"
184
#include "block/block_int.h"
185
+#include "block/qdict.h"
186
#include "sysemu/block-backend.h"
187
#include "qemu/module.h"
188
#include "qemu/option.h"
189
diff --git a/block/qcow.c b/block/qcow.c
190
index XXXXXXX..XXXXXXX 100644
191
--- a/block/qcow.c
192
+++ b/block/qcow.c
193
@@ -XXX,XX +XXX,XX @@
194
#include "qapi/error.h"
195
#include "qemu/error-report.h"
196
#include "block/block_int.h"
197
+#include "block/qdict.h"
198
#include "sysemu/block-backend.h"
199
#include "qemu/module.h"
200
#include "qemu/option.h"
201
diff --git a/block/qcow2.c b/block/qcow2.c
202
index XXXXXXX..XXXXXXX 100644
203
--- a/block/qcow2.c
204
+++ b/block/qcow2.c
205
@@ -XXX,XX +XXX,XX @@
206
207
#include "qemu/osdep.h"
208
#include "block/block_int.h"
209
+#include "block/qdict.h"
210
#include "sysemu/block-backend.h"
211
#include "qemu/module.h"
212
#include <zlib.h>
213
diff --git a/block/qed.c b/block/qed.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/block/qed.c
216
+++ b/block/qed.c
217
@@ -XXX,XX +XXX,XX @@
218
*/
219
220
#include "qemu/osdep.h"
221
+#include "block/qdict.h"
222
#include "qapi/error.h"
223
#include "qemu/timer.h"
224
#include "qemu/bswap.h"
225
diff --git a/block/quorum.c b/block/quorum.c
226
index XXXXXXX..XXXXXXX 100644
227
--- a/block/quorum.c
228
+++ b/block/quorum.c
229
@@ -XXX,XX +XXX,XX @@
230
#include "qemu/cutils.h"
231
#include "qemu/option.h"
232
#include "block/block_int.h"
233
+#include "block/qdict.h"
234
#include "qapi/error.h"
235
#include "qapi/qapi-events-block.h"
236
#include "qapi/qmp/qdict.h"
237
diff --git a/block/rbd.c b/block/rbd.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/block/rbd.c
240
+++ b/block/rbd.c
241
@@ -XXX,XX +XXX,XX @@
242
#include "qemu/error-report.h"
243
#include "qemu/option.h"
244
#include "block/block_int.h"
245
+#include "block/qdict.h"
246
#include "crypto/secret.h"
247
#include "qemu/cutils.h"
248
#include "qapi/qmp/qstring.h"
249
diff --git a/block/sheepdog.c b/block/sheepdog.c
250
index XXXXXXX..XXXXXXX 100644
251
--- a/block/sheepdog.c
252
+++ b/block/sheepdog.c
253
@@ -XXX,XX +XXX,XX @@
254
#include "qemu/option.h"
255
#include "qemu/sockets.h"
256
#include "block/block_int.h"
257
+#include "block/qdict.h"
258
#include "sysemu/block-backend.h"
259
#include "qemu/bitops.h"
260
#include "qemu/cutils.h"
261
diff --git a/block/snapshot.c b/block/snapshot.c
262
index XXXXXXX..XXXXXXX 100644
263
--- a/block/snapshot.c
264
+++ b/block/snapshot.c
265
@@ -XXX,XX +XXX,XX @@
266
#include "qemu/osdep.h"
267
#include "block/snapshot.h"
268
#include "block/block_int.h"
269
+#include "block/qdict.h"
270
#include "qapi/error.h"
271
#include "qapi/qmp/qdict.h"
272
#include "qapi/qmp/qerror.h"
273
diff --git a/block/ssh.c b/block/ssh.c
274
index XXXXXXX..XXXXXXX 100644
275
--- a/block/ssh.c
276
+++ b/block/ssh.c
277
@@ -XXX,XX +XXX,XX @@
278
#include <libssh2_sftp.h>
279
280
#include "block/block_int.h"
281
+#include "block/qdict.h"
282
#include "qapi/error.h"
283
#include "qemu/error-report.h"
284
#include "qemu/option.h"
285
diff --git a/block/vhdx.c b/block/vhdx.c
286
index XXXXXXX..XXXXXXX 100644
287
--- a/block/vhdx.c
288
+++ b/block/vhdx.c
289
@@ -XXX,XX +XXX,XX @@
290
#include "qemu/osdep.h"
291
#include "qapi/error.h"
292
#include "block/block_int.h"
293
+#include "block/qdict.h"
294
#include "sysemu/block-backend.h"
295
#include "qemu/module.h"
296
#include "qemu/option.h"
297
diff --git a/block/vpc.c b/block/vpc.c
298
index XXXXXXX..XXXXXXX 100644
299
--- a/block/vpc.c
300
+++ b/block/vpc.c
301
@@ -XXX,XX +XXX,XX @@
302
#include "qemu/osdep.h"
303
#include "qapi/error.h"
304
#include "block/block_int.h"
305
+#include "block/qdict.h"
306
#include "sysemu/block-backend.h"
307
#include "qemu/module.h"
308
#include "qemu/option.h"
309
diff --git a/block/vvfat.c b/block/vvfat.c
310
index XXXXXXX..XXXXXXX 100644
311
--- a/block/vvfat.c
312
+++ b/block/vvfat.c
313
@@ -XXX,XX +XXX,XX @@
314
#include <dirent.h>
315
#include "qapi/error.h"
316
#include "block/block_int.h"
317
+#include "block/qdict.h"
318
#include "qemu/module.h"
319
#include "qemu/option.h"
320
#include "qemu/bswap.h"
321
diff --git a/block/vxhs.c b/block/vxhs.c
322
index XXXXXXX..XXXXXXX 100644
323
--- a/block/vxhs.c
324
+++ b/block/vxhs.c
325
@@ -XXX,XX +XXX,XX @@
326
#include <qnio/qnio_api.h>
327
#include <sys/param.h>
328
#include "block/block_int.h"
329
+#include "block/qdict.h"
330
#include "qapi/qmp/qerror.h"
331
#include "qapi/qmp/qdict.h"
332
#include "qapi/qmp/qstring.h"
333
diff --git a/blockdev.c b/blockdev.c
334
index XXXXXXX..XXXXXXX 100644
335
--- a/blockdev.c
336
+++ b/blockdev.c
337
@@ -XXX,XX +XXX,XX @@
338
#include "sysemu/blockdev.h"
339
#include "hw/block/block.h"
340
#include "block/blockjob.h"
341
+#include "block/qdict.h"
342
#include "block/throttle-groups.h"
343
#include "monitor/monitor.h"
344
#include "qemu/error-report.h"
345
diff --git a/qobject/qdict.c b/qobject/qdict.c
346
index XXXXXXX..XXXXXXX 100644
347
--- a/qobject/qdict.c
348
+++ b/qobject/qdict.c
349
@@ -XXX,XX +XXX,XX @@
350
*/
351
352
#include "qemu/osdep.h"
353
+#include "block/qdict.h"
354
#include "qapi/qmp/qnum.h"
355
#include "qapi/qmp/qdict.h"
356
#include "qapi/qmp/qbool.h"
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"
403
--
404
2.13.6
405
406
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
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>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
qobject/block-qdict.c | 640 ++++++++++++++++++++++++++++++++++++++++++++
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
20
21
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
22
new file mode 100644
23
index XXXXXXX..XXXXXXX
24
--- /dev/null
25
+++ b/qobject/block-qdict.c
26
@@ -XXX,XX +XXX,XX @@
27
+/*
28
+ * Special QDict functions used by the block layer
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;
53
+ }
54
+
55
+ val = qdict_get(src, key);
56
+ if (val) {
57
+ qdict_put_obj(dst, key, qobject_ref(val));
58
+ }
59
+}
60
+
61
+/**
62
+ * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
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));
103
+ }
104
+
105
+ g_free(new_key);
106
+ }
107
+}
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;
370
+ }
371
+ }
372
+ }
373
+
374
+ if (is_list == -1) {
375
+ assert(!qdict_size(maybe_list));
376
+ is_list = 0;
377
+ }
378
+
379
+ /* NB this isn't a perfect check - e.g. it won't catch
380
+ * a list containing '1', '+1', '01', '3', but that
381
+ * does not matter - we've still proved that the
382
+ * input is a list. It is up the caller to do a
383
+ * stricter check if desired */
384
+ if (len != (max + 1)) {
385
+ error_setg(errp, "List indices are not contiguous, "
386
+ "saw %zd elements but %zd largest index",
387
+ len, max);
388
+ return -1;
389
+ }
390
+
391
+ return is_list;
392
+}
393
+
394
+/**
395
+ * qdict_crumple:
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;
705
- }
706
-
707
- val = qdict_get(src, key);
708
- if (val) {
709
- qdict_put_obj(dst, key, qobject_ref(val));
710
- }
711
-}
712
-
713
-/**
714
- * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
715
- * new QString initialised by 'val' is put there.
716
- */
717
-void qdict_set_default_str(QDict *dst, const char *key, const char *val)
718
-{
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++;
854
- }
855
- }
856
-
857
- return count;
858
-}
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)
2711
--
2712
2.13.6
2713
2714
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
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>
66
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
67
---
68
include/block/qdict.h | 1 +
69
block/nfs.c | 2 +-
70
block/parallels.c | 2 +-
71
block/qcow.c | 2 +-
72
block/qcow2.c | 2 +-
73
block/qed.c | 2 +-
74
block/rbd.c | 2 +-
75
block/sheepdog.c | 2 +-
76
block/vhdx.c | 2 +-
77
block/vpc.c | 2 +-
78
qobject/block-qdict.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
79
11 files changed, 67 insertions(+), 9 deletions(-)
80
81
diff --git a/include/block/qdict.h b/include/block/qdict.h
82
index XXXXXXX..XXXXXXX 100644
83
--- a/include/block/qdict.h
84
+++ b/include/block/qdict.h
85
@@ -XXX,XX +XXX,XX @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
86
void qdict_array_split(QDict *src, QList **dst);
87
int qdict_array_entries(QDict *src, const char *subqdict);
88
QObject *qdict_crumple(const QDict *src, Error **errp);
89
+QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp);
90
void qdict_flatten(QDict *qdict);
91
92
typedef struct QDictRenames {
93
diff --git a/block/nfs.c b/block/nfs.c
94
index XXXXXXX..XXXXXXX 100644
95
--- a/block/nfs.c
96
+++ b/block/nfs.c
97
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
98
const QDictEntry *e;
99
Error *local_err = NULL;
100
101
- crumpled = qdict_crumple(options, errp);
102
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
103
if (crumpled == NULL) {
104
return NULL;
105
}
106
diff --git a/block/parallels.c b/block/parallels.c
107
index XXXXXXX..XXXXXXX 100644
108
--- a/block/parallels.c
109
+++ b/block/parallels.c
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
111
qdict_put_str(qdict, "driver", "parallels");
112
qdict_put_str(qdict, "file", bs->node_name);
113
114
- qobj = qdict_crumple(qdict, errp);
115
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
116
qobject_unref(qdict);
117
qdict = qobject_to(QDict, qobj);
118
if (qdict == NULL) {
119
diff --git a/block/qcow.c b/block/qcow.c
120
index XXXXXXX..XXXXXXX 100644
121
--- a/block/qcow.c
122
+++ b/block/qcow.c
123
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
124
qdict_put_str(qdict, "driver", "qcow");
125
qdict_put_str(qdict, "file", bs->node_name);
126
127
- qobj = qdict_crumple(qdict, errp);
128
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
129
qobject_unref(qdict);
130
qdict = qobject_to(QDict, qobj);
131
if (qdict == NULL) {
132
diff --git a/block/qcow2.c b/block/qcow2.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/block/qcow2.c
135
+++ b/block/qcow2.c
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
137
qdict_put_str(qdict, "file", bs->node_name);
138
139
/* Now get the QAPI type BlockdevCreateOptions */
140
- qobj = qdict_crumple(qdict, errp);
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,
163
}
164
165
/* Convert the remaining options into a QAPI object */
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;
183
goto fail;
184
diff --git a/block/vhdx.c b/block/vhdx.c
185
index XXXXXXX..XXXXXXX 100644
186
--- a/block/vhdx.c
187
+++ b/block/vhdx.c
188
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
189
qdict_put_str(qdict, "driver", "vhdx");
190
qdict_put_str(qdict, "file", bs->node_name);
191
192
- qobj = qdict_crumple(qdict, errp);
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)
226
}
227
228
/**
229
+ * qdict_crumple_for_keyval_qiv:
230
+ * @src: the flat dictionary (only scalar values) to crumple
231
+ * @errp: location to store error
232
+ *
233
+ * Like qdict_crumple(), but additionally transforms scalar values so
234
+ * the result can be passed to qobject_input_visitor_new_keyval().
235
+ *
236
+ * The block subsystem uses this function to prepare its flat QDict
237
+ * with possibly confused scalar types for a visit. It should not be
238
+ * used for anything else, and it should go away once the block
239
+ * subsystem has been cleaned up.
240
+ */
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
286
--
287
2.13.6
288
289
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
The previous commit fixed -blockdev breakage due to misuse of the
4
qobject input visitor's keyval flavor in bdrv_file_open(). The commit
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:
9
10
$ qemu-system-x86 -drive node-name=n1,driver=nbd,server.type=inet,server.host=localhost,server.port=1234,server.numeric=off
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
12
13
Fix it the same way: replace qdict_crumple() by
14
qdict_crumple_for_keyval_qiv(), and switch from plain to the keyval
15
flavor.
16
17
Signed-off-by: Markus Armbruster <armbru@redhat.com>
18
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
21
block/nbd.c | 12 ++----------
22
block/sheepdog.c | 12 ++----------
23
block/ssh.c | 12 ++----------
24
3 files changed, 6 insertions(+), 30 deletions(-)
25
26
diff --git a/block/nbd.c b/block/nbd.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/nbd.c
29
+++ b/block/nbd.c
30
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
31
goto done;
32
}
33
34
- crumpled_addr = qdict_crumple(addr, errp);
35
+ crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp);
36
if (!crumpled_addr) {
37
goto done;
38
}
39
40
- /*
41
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
42
- * server.type=inet. .to doesn't matter, it's ignored anyway.
43
- * That's because when @options come from -blockdev or
44
- * blockdev_add, members are typed according to the QAPI schema,
45
- * but when they come from -drive, they're all QString. The
46
- * visitor expects the former.
47
- */
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;
65
}
66
67
- /*
68
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
69
- * server.type=inet. .to doesn't matter, it's ignored anyway.
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);
107
--
108
2.13.6
109
110
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
The following pattern occurs in the .bdrv_co_create_opts() methods of
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>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
30
block/parallels.c | 9 ++++-----
31
block/qcow.c | 9 ++++-----
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
100
diff --git a/block/qcow2.c b/block/qcow2.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/qcow2.c
103
+++ b/block/qcow2.c
104
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
105
Error **errp)
106
{
107
BlockdevCreateOptions *create_options = NULL;
108
- QDict *qdict = NULL;
109
+ QDict *qdict;
110
QObject *qobj;
111
Visitor *v;
112
BlockDriverState *bs = NULL;
113
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
114
115
/* Now get the QAPI type BlockdevCreateOptions */
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
224
--
225
2.13.6
226
227
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
include/block/qdict.h | 3 ++-
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(-)
21
22
diff --git a/include/block/qdict.h b/include/block/qdict.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/qdict.h
25
+++ b/include/block/qdict.h
26
@@ -XXX,XX +XXX,XX @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
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;
75
}
76
diff --git a/block/nfs.c b/block/nfs.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/block/nfs.c
79
+++ b/block/nfs.c
80
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
81
Error **errp)
82
{
83
BlockdevOptionsNfs *opts = NULL;
84
- QObject *crumpled = NULL;
85
Visitor *v;
86
const QDictEntry *e;
87
Error *local_err = NULL;
88
89
- crumpled = qdict_crumple_for_keyval_qiv(options, errp);
90
- if (crumpled == NULL) {
91
+ v = qobject_input_visitor_new_flat_confused(options, errp);
92
+ if (!v) {
93
return NULL;
94
}
95
96
- v = qobject_input_visitor_new_keyval(crumpled);
97
visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
98
visit_free(v);
99
- qobject_unref(crumpled);
100
101
if (local_err) {
102
error_propagate(errp, local_err);
103
diff --git a/block/parallels.c b/block/parallels.c
104
index XXXXXXX..XXXXXXX 100644
105
--- a/block/parallels.c
106
+++ b/block/parallels.c
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;
124
goto done;
125
}
126
127
- v = qobject_input_visitor_new_keyval(qobj);
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
278
done:
279
visit_free(iv);
280
- qobject_unref(crumpled_server);
281
qobject_unref(server);
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
}
424
+
425
+/*
426
+ * Create a QObject input visitor for flat @qdict with possibly
427
+ * confused scalar types.
428
+ *
429
+ * The block subsystem uses this function to visit its flat QDict with
430
+ * possibly confused scalar types. It should not be used for anything
431
+ * else, and it should go away once the block subsystem has been
432
+ * cleaned up.
433
+ */
434
+Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict,
435
+ Error **errp)
436
+{
437
+ QObject *crumpled;
438
+ Visitor *v;
439
+
440
+ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
441
+ if (!crumpled) {
442
+ return NULL;
443
+ }
444
+
445
+ v = qobject_input_visitor_new_keyval(crumpled);
446
+ qobject_unref(crumpled);
447
+ return v;
448
+}
449
--
450
2.13.6
451
452
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
Remaining uses of qobject_input_visitor_new_keyval() in the block
4
subsystem:
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>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
30
block/crypto.c | 12 +++++++++---
31
block/vdi.c | 8 ++++++--
32
2 files changed, 15 insertions(+), 5 deletions(-)
33
34
diff --git a/block/crypto.c b/block/crypto.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/crypto.c
37
+++ b/block/crypto.c
38
@@ -XXX,XX +XXX,XX @@
39
#include "qemu/osdep.h"
40
41
#include "block/block_int.h"
42
+#include "block/qdict.h"
43
#include "sysemu/block-backend.h"
44
#include "crypto/block.h"
45
#include "qapi/opts-visitor.h"
46
#include "qapi/qapi-visit-crypto.h"
47
-#include "qapi/qmp/qdict.h"
48
#include "qapi/qobject-input-visitor.h"
49
#include "qapi/error.h"
50
#include "qemu/option.h"
51
@@ -XXX,XX +XXX,XX @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
52
ret = g_new0(QCryptoBlockOpenOptions, 1);
53
ret->format = format;
54
55
- v = qobject_input_visitor_new_keyval(QOBJECT(opts));
56
+ v = qobject_input_visitor_new_flat_confused(opts, &local_err);
57
+ if (local_err) {
58
+ goto out;
59
+ }
60
61
visit_start_struct(v, NULL, NULL, 0, &local_err);
62
if (local_err) {
63
@@ -XXX,XX +XXX,XX @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
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
104
--
105
2.13.6
106
107
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
There's no need to restart the loop. We don't elsewhere, e.g. in
4
qdict_extract_subqdict(), qdict_join() and qemu_opts_absorb_qdict().
5
Simplify accordingly.
6
7
Signed-off-by: Markus Armbruster <armbru@redhat.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
qobject/block-qdict.c | 18 +++---------------
12
1 file changed, 3 insertions(+), 15 deletions(-)
13
14
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/qobject/block-qdict.c
17
+++ b/qobject/block-qdict.c
18
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
19
QObject *value;
20
const QDictEntry *entry, *next;
21
char *new_key;
22
- bool delete;
23
24
entry = qdict_first(qdict);
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
}
65
}
66
--
67
2.13.6
68
69
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
qdict_flatten_qdict() skips copying scalars from @qdict to @target
4
when the two are the same. Fair enough, but it uses a non-obvious
5
test for "same". Replace it by the obvious one. While there, improve
6
comments.
7
8
Signed-off-by: Markus Armbruster <armbru@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
qobject/block-qdict.c | 14 +++++++++-----
13
1 file changed, 9 insertions(+), 5 deletions(-)
14
15
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qobject/block-qdict.c
18
+++ b/qobject/block-qdict.c
19
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
20
value = qlist_entry_obj(entry);
21
new_key = g_strdup_printf("%s.%i", prefix, i);
22
23
+ /*
24
+ * Flatten non-empty QDict and QList recursively into @target,
25
+ * copy other objects to @target
26
+ */
27
if (qobject_type(value) == QTYPE_QDICT) {
28
qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
29
} else if (qobject_type(value) == QTYPE_QLIST) {
30
qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
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);
59
}
60
--
61
2.13.6
62
63
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
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
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
qobject/block-qdict.c | 27 +++++++++++----------------
8
1 file changed, 11 insertions(+), 16 deletions(-)
9
10
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/qobject/block-qdict.c
13
+++ b/qobject/block-qdict.c
14
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
15
16
for (ent = qdict_first(maybe_list); ent != NULL;
17
ent = qdict_next(maybe_list, ent)) {
18
+ int is_index = !qemu_strtoi64(ent->key, NULL, 10, &val);
19
20
- if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
21
- if (is_list == -1) {
22
- is_list = 1;
23
- } else if (!is_list) {
24
- error_setg(errp,
25
- "Cannot mix list and non-list keys");
26
- return -1;
27
- }
28
+ if (is_list == -1) {
29
+ is_list = is_index;
30
+ }
31
+
32
+ if (is_index != is_list) {
33
+ error_setg(errp, "Cannot mix list and non-list keys");
34
+ return -1;
35
+ }
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
}
51
}
52
53
--
54
2.13.6
55
56
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/check-block-qdict.c | 57 ++++++++++++++++++++++++-----------------------
8
1 file changed, 29 insertions(+), 28 deletions(-)
9
10
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/check-block-qdict.c
13
+++ b/tests/check-block-qdict.c
14
@@ -XXX,XX +XXX,XX @@ static void qdict_defaults_test(void)
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);
88
}
89
90
static void qdict_array_split_test(void)
91
--
92
2.13.6
93
94
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/check-block-qdict.c | 14 +++++++++++++-
8
1 file changed, 13 insertions(+), 1 deletion(-)
9
10
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/check-block-qdict.c
13
+++ b/tests/check-block-qdict.c
14
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
15
QList *e = qlist_new();
16
QDict *e_1_2 = qdict_new();
17
QDict *f = qdict_new();
18
+ QList *y = qlist_new();
19
+ QDict *z = qdict_new();
20
QDict *root = qdict_new();
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);
58
59
--
60
2.13.6
61
62
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
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
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
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>
62
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
63
---
64
qapi/block-core.json | 13 +++++++++++++
65
block/rbd.c | 42 ++++++++++++++++++++++++++++++++----------
66
2 files changed, 45 insertions(+), 10 deletions(-)
67
68
diff --git a/qapi/block-core.json b/qapi/block-core.json
69
index XXXXXXX..XXXXXXX 100644
70
--- a/qapi/block-core.json
71
+++ b/qapi/block-core.json
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);
138
}
139
140
- rados_conf_set(cluster, "key", secret);
141
- g_free(secret);
142
+ if (opts->has_auth_client_required) {
143
+ accu = g_string_new("");
144
+ for (auth = opts->auth_client_required; auth; auth = auth->next) {
145
+ if (accu->str[0]) {
146
+ g_string_append_c(accu, ';');
147
+ }
148
+ g_string_append(accu, RbdAuthMode_str(auth->value));
149
+ }
150
+ acr = g_string_free(accu, FALSE);
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
}
164
}
165
166
- if (qemu_rbd_set_auth(*cluster, secretid, errp) < 0) {
167
+ if (qemu_rbd_set_auth(*cluster, secretid, opts, errp) < 0) {
168
r = -EIO;
169
goto failed_shutdown;
170
}
171
--
172
2.13.6
173
174
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
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>
33
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
---
35
qapi/block-core.json | 6 ++++++
36
block/rbd.c | 41 +++++++++++++++++++++++++----------------
37
2 files changed, 31 insertions(+), 16 deletions(-)
38
39
diff --git a/qapi/block-core.json b/qapi/block-core.json
40
index XXXXXXX..XXXXXXX 100644
41
--- a/qapi/block-core.json
42
+++ b/qapi/block-core.json
43
@@ -XXX,XX +XXX,XX @@
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)
68
}
69
70
71
-static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
72
- BlockdevOptionsRbd *opts,
73
+static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts,
74
Error **errp)
75
{
76
- char *acr;
77
+ char *key, *acr;
78
int r;
79
GString *accu;
80
RbdAuthModeList *auth;
81
82
- if (secretid) {
83
- gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
84
- errp);
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);
101
}
102
103
if (opts->has_auth_client_required) {
104
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
105
},
106
};
107
108
-/* FIXME Deprecate and remove keypairs or make it available in QMP.
109
- * password_secret should eventually be configurable in opts->location. Support
110
- * for it in .bdrv_open will make it work here as well. */
111
+/* FIXME Deprecate and remove keypairs or make it available in QMP. */
112
static int qemu_rbd_do_create(BlockdevCreateOptions *options,
113
const char *keypairs, const char *password_secret,
114
Error **errp)
115
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
116
Error *local_err = NULL;
117
int r;
118
119
+ if (secretid) {
120
+ if (opts->key_secret) {
121
+ error_setg(errp,
122
+ "Legacy 'password-secret' clashes with 'key-secret'");
123
+ return -EINVAL;
124
+ }
125
+ opts->key_secret = g_strdup(secretid);
126
+ opts->has_key_secret = true;
127
+ }
128
+
129
mon_host = qemu_rbd_mon_host(opts, &local_err);
130
if (local_err) {
131
error_propagate(errp, local_err);
132
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
133
}
134
}
135
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;
141
}
142
143
--
144
2.13.6
145
146
diff view generated by jsdifflib
Deleted patch
1
The -drive options cyls, heads, secs and trans were deprecated in
2
QEMU 2.10. It's time to remove them.
3
1
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
Deleted patch
1
The -drive option addr was deprecated in QEMU 2.10. It's time to remove
2
it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
8
include/sysemu/blockdev.h | 1 -
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(-)
14
15
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/sysemu/blockdev.h
18
+++ b/include/sysemu/blockdev.h
19
@@ -XXX,XX +XXX,XX @@ typedef enum {
20
} BlockInterfaceType;
21
22
struct DriveInfo {
23
- const char *devaddr;
24
BlockInterfaceType type;
25
int bus;
26
int unit;
27
diff --git a/blockdev.c b/blockdev.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/blockdev.c
30
+++ b/blockdev.c
31
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
32
.type = QEMU_OPT_STRING,
33
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
34
},{
35
- .name = "addr",
36
- .type = QEMU_OPT_STRING,
37
- .help = "pci address (virtio only)",
38
- },{
39
.name = "serial",
40
.type = QEMU_OPT_STRING,
41
.help = "disk serial number",
42
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
43
DriveMediaType media = MEDIA_DISK;
44
BlockInterfaceType type;
45
int max_devs, bus_id, unit_id, index;
46
- const char *devaddr;
47
const char *werror, *rerror;
48
bool read_only = false;
49
bool copy_on_read;
50
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
51
Error *local_err = NULL;
52
int i;
53
const char *deprecated[] = {
54
- "serial", "addr"
55
+ "serial"
56
};
57
58
/* Change legacy command line options into QMP ones */
59
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
60
}
61
62
/* Add virtio block device */
63
- devaddr = qemu_opt_get(legacy_opts, "addr");
64
- if (devaddr && type != IF_VIRTIO) {
65
- error_report("addr is not supported by this bus type");
66
- goto fail;
67
- }
68
-
69
if (type == IF_VIRTIO) {
70
QemuOpts *devopts;
71
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
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
- }
79
}
80
81
filename = qemu_opt_get(legacy_opts, "file");
82
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
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)
114
-
115
-The drive addr argument is replaced by the the addr argument
116
-that can be specified with the ``-device'' parameter.
117
-
118
@subsection -usbdevice (since 2.10.0)
119
120
The ``-usbdevice DEV'' argument is now a synonym for setting
121
diff --git a/qemu-options.hx b/qemu-options.hx
122
index XXXXXXX..XXXXXXX 100644
123
--- a/qemu-options.hx
124
+++ b/qemu-options.hx
125
@@ -XXX,XX +XXX,XX @@ ETEXI
126
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
127
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
128
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
129
- " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
130
+ " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
131
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
132
" [,readonly=on|off][,copy-on-read=on|off]\n"
133
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
134
@@ -XXX,XX +XXX,XX @@ an untrusted format header.
135
This option specifies the serial number to assign to the device. This
136
parameter is deprecated, use the corresponding parameter of @code{-device}
137
instead.
138
-@item addr=@var{addr}
139
-Specify the controller's PCI address (if=virtio only). This parameter is
140
-deprecated, use the corresponding parameter of @code{-device} instead.
141
@item werror=@var{action},rerror=@var{action}
142
Specify which @var{action} to take on write and read errors. Valid actions are:
143
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
144
--
145
2.13.6
146
147
diff view generated by jsdifflib
Deleted patch
1
The -drive option serial was deprecated in QEMU 2.10. It's time to
2
remove it.
3
1
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
Deleted patch
1
We removed all options from the 'deprecated' array, so the code is dead
2
and can be removed as well.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
---
7
blockdev.c | 12 ------------
8
1 file changed, 12 deletions(-)
9
10
diff --git a/blockdev.c b/blockdev.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/blockdev.c
13
+++ b/blockdev.c
14
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
15
const char *filename;
16
Error *local_err = NULL;
17
int i;
18
- const char *deprecated[] = {
19
- };
20
21
/* Change legacy command line options into QMP ones */
22
static const struct {
23
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
24
goto fail;
25
}
26
27
- /* Other deprecated options */
28
- if (!qtest_enabled()) {
29
- for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
30
- if (qemu_opt_get(legacy_opts, deprecated[i]) != NULL) {
31
- error_report("'%s' is deprecated, please use the corresponding "
32
- "option of '-device' instead", deprecated[i]);
33
- }
34
- }
35
- }
36
-
37
/* Media type */
38
value = qemu_opt_get(legacy_opts, "media");
39
if (value) {
40
--
41
2.13.6
42
43
diff view generated by jsdifflib