1
The following changes since commit 91fe7a376ad46e3cc5e82d418aad22173c948a3c:
1
The following changes since commit 52ed34cbddde1cb89b2ac263e758e349a77f21e1:
2
2
3
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging (2018-06-15 11:41:44 +0100)
3
Merge tag 'pull-request-2023-06-26' of https://gitlab.com/thuth/qemu into staging (2023-06-26 10:38:41 +0200)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
https://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 6266e900b8083945cb766b45c124fb3c42932cb3:
9
for you to fetch changes up to 17362398ee1a7f04e8006a46333145d8b707fd35:
10
10
11
block: Remove dead deprecation warning code (2018-06-15 14:49:44 +0200)
11
block: use bdrv_co_debug_event in coroutine context (2023-06-28 09:46:34 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- Fix options that work only with -drive or -blockdev, but not with
16
- Re-enable the graph lock
17
both, because of QDict type confusion
17
- More fixes to coroutine_fn marking
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
18
24
----------------------------------------------------------------
19
----------------------------------------------------------------
25
Eric Blake (2):
20
Kevin Wolf (11):
26
qemu-img: Fix assert when mapping unaligned raw file
21
iotests: Test active commit with iothread and background I/O
27
iotests: Add test 221 to catch qemu-img map regression
22
qdev-properties-system: Lock AioContext for blk_insert_bs()
23
test-block-iothread: Lock AioContext for blk_insert_bs()
24
block: Fix AioContext locking in bdrv_open_child()
25
block: Fix AioContext locking in bdrv_attach_child_common()
26
block: Fix AioContext locking in bdrv_reopen_parse_file_or_backing()
27
block: Fix AioContext locking in bdrv_open_inherit()
28
block: Fix AioContext locking in bdrv_open_backing_file()
29
blockjob: Fix AioContext locking in block_job_add_bdrv()
30
graph-lock: Unlock the AioContext while polling
31
Revert "graph-lock: Disable locking for now"
28
32
29
John Snow (2):
33
Paolo Bonzini (12):
30
jobs: fix stale wording
34
file-posix: remove incorrect coroutine_fn calls
31
jobs: fix verb references in docs
35
qed: mark more functions as coroutine_fns and GRAPH_RDLOCK
36
vpc: mark more functions as coroutine_fns and GRAPH_RDLOCK
37
bochs: mark more functions as coroutine_fns and GRAPH_RDLOCK
38
block: mark another function as coroutine_fns and GRAPH_UNLOCKED
39
cloop: mark more functions as coroutine_fns and GRAPH_RDLOCK
40
dmg: mark more functions as coroutine_fns and GRAPH_RDLOCK
41
vmdk: mark more functions as coroutine_fns and GRAPH_RDLOCK
42
vhdx: mark more functions as coroutine_fns and GRAPH_RDLOCK
43
qcow2: mark more functions as coroutine_fns and GRAPH_RDLOCK
44
block: use bdrv_co_getlength in coroutine context
45
block: use bdrv_co_debug_event in coroutine context
32
46
33
Kevin Wolf (4):
47
block/qcow2.h | 33 +++--
34
block: Remove deprecated -drive geometry options
48
block/vhdx.h | 5 +-
35
block: Remove deprecated -drive option addr
49
include/block/block-io.h | 7 ++
36
block: Remove deprecated -drive option serial
50
include/block/graph-lock.h | 6 +-
37
block: Remove dead deprecation warning code
51
block.c | 114 ++++++++++++++++--
38
52
block/bochs.c | 7 +-
39
Markus Armbruster (17):
53
block/cloop.c | 9 +-
40
rbd: Drop deprecated -drive parameter "filename"
54
block/dmg.c | 21 ++--
41
iscsi: Drop deprecated -drive parameter "filename"
55
block/file-posix.c | 29 +++--
42
qobject: Move block-specific qdict code to block-qdict.c
56
block/graph-lock.c | 43 +++----
43
block: Fix -blockdev for certain non-string scalars
57
block/io.c | 14 +--
44
block: Fix -drive for certain non-string scalars
58
block/parallels.c | 4 +-
45
block: Clean up a misuse of qobject_to() in .bdrv_co_create_opts()
59
block/qcow.c | 30 ++---
46
block: Factor out qobject_input_visitor_new_flat_confused()
60
block/qcow2-bitmap.c | 26 ++--
47
block: Make remaining uses of qobject input visitor more robust
61
block/qcow2-cluster.c | 24 ++--
48
block-qdict: Simplify qdict_flatten_qdict()
62
block/qcow2-refcount.c | 134 +++++++++++----------
49
block-qdict: Tweak qdict_flatten_qdict(), qdict_flatten_qlist()
63
block/qcow2.c | 20 +--
50
block-qdict: Clean up qdict_crumple() a bit
64
block/qed-check.c | 5 +-
51
block-qdict: Simplify qdict_is_list() some
65
block/qed-table.c | 6 +-
52
check-block-qdict: Rename qdict_flatten()'s variables for clarity
66
block/qed.c | 15 +--
53
check-block-qdict: Cover flattening of empty lists and dictionaries
67
block/raw-format.c | 4 +-
54
block: Fix -blockdev / blockdev-add for empty objects and arrays
68
block/vhdx-log.c | 36 +++---
55
rbd: New parameter auth-client-required
69
block/vhdx.c | 73 ++++++-----
56
rbd: New parameter key-secret
70
block/vmdk.c | 55 ++++-----
57
71
block/vpc.c | 52 ++++----
58
Max Reitz (1):
72
blockjob.c | 17 ++-
59
block: Add block-specific QDict header
73
hw/core/qdev-properties-system.c | 8 +-
60
74
tests/unit/test-block-iothread.c | 7 +-
61
qapi/block-core.json | 19 ++
75
tests/qemu-iotests/tests/iothreads-commit-active | 85 +++++++++++++
62
qapi/job.json | 23 +-
76
.../qemu-iotests/tests/iothreads-commit-active.out | 23 ++++
63
include/block/qdict.h | 34 +++
77
30 files changed, 573 insertions(+), 339 deletions(-)
64
include/hw/block/block.h | 1 -
78
create mode 100755 tests/qemu-iotests/tests/iothreads-commit-active
65
include/qapi/qmp/qdict.h | 17 --
79
create mode 100644 tests/qemu-iotests/tests/iothreads-commit-active.out
66
include/sysemu/blockdev.h | 3 -
67
block.c | 1 +
68
block/block-backend.c | 1 -
69
block/crypto.c | 12 +-
70
block/gluster.c | 1 +
71
block/iscsi.c | 24 +-
72
block/nbd.c | 16 +-
73
block/nfs.c | 8 +-
74
block/parallels.c | 11 +-
75
block/qcow.c | 11 +-
76
block/qcow2.c | 11 +-
77
block/qed.c | 11 +-
78
block/quorum.c | 1 +
79
block/rbd.c | 85 +++---
80
block/sheepdog.c | 23 +-
81
block/snapshot.c | 1 +
82
block/ssh.c | 16 +-
83
block/vdi.c | 8 +-
84
block/vhdx.c | 11 +-
85
block/vpc.c | 11 +-
86
block/vvfat.c | 1 +
87
block/vxhs.c | 1 +
88
blockdev.c | 111 +------
89
device-hotplug.c | 4 -
90
hw/block/block.c | 27 --
91
hw/block/nvme.c | 1 -
92
hw/block/virtio-blk.c | 1 -
93
hw/ide/qdev.c | 1 -
94
hw/scsi/scsi-disk.c | 1 -
95
hw/usb/dev-storage.c | 1 -
96
qemu-img.c | 2 +-
97
qobject/block-qdict.c | 722 +++++++++++++++++++++++++++++++++++++++++++++
98
qobject/qdict.c | 628 ---------------------------------------
99
tests/ahci-test.c | 6 +-
100
tests/check-block-qdict.c | 690 +++++++++++++++++++++++++++++++++++++++++++
101
tests/check-qdict.c | 641 ----------------------------------------
102
tests/check-qobject.c | 1 +
103
tests/hd-geo-test.c | 37 +--
104
tests/ide-test.c | 8 +-
105
tests/test-replication.c | 1 +
106
util/qemu-config.c | 1 +
107
MAINTAINERS | 2 +
108
hmp-commands.hx | 1 -
109
qemu-doc.texi | 15 -
110
qemu-options.hx | 14 +-
111
qobject/Makefile.objs | 1 +
112
tests/Makefile.include | 4 +
113
tests/qemu-iotests/221 | 60 ++++
114
tests/qemu-iotests/221.out | 16 +
115
tests/qemu-iotests/group | 1 +
116
55 files changed, 1692 insertions(+), 1668 deletions(-)
117
create mode 100644 include/block/qdict.h
118
create mode 100644 qobject/block-qdict.c
119
create mode 100644 tests/check-block-qdict.c
120
create mode 100755 tests/qemu-iotests/221
121
create mode 100644 tests/qemu-iotests/221.out
122
diff view generated by jsdifflib
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
1
From: Eric Blake <eblake@redhat.com>
1
This is a better regression test for the bugs hidden by commit 80fc5d26
2
('graph-lock: Disable locking for now'). With that commit reverted, it
3
hangs instantaneously and reliably for me.
2
4
3
Although qemu-img creates aligned files (by rounding up), it
5
It is important to have a reliable test like this, because the following
4
must also gracefully handle files that are not sector-aligned.
6
commits will set out to fix the actual root cause of the deadlocks and
5
Test that the bug fixed in the previous patch does not recur.
7
then finally revert commit 80fc5d26, which was only a stopgap solution.
6
8
7
It's a bit annoying that we can see the (implicit) hole past
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
the end of the file on to the next sector boundary, so if we
10
Message-ID: <20230605085711.21261-2-kwolf@redhat.com>
9
ever reach the point where we report a byte-accurate size rather
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
13
---
16
tests/qemu-iotests/221 | 60 ++++++++++++++++++++++++++++++++++++++++++++++
14
.../tests/iothreads-commit-active | 85 +++++++++++++++++++
17
tests/qemu-iotests/221.out | 16 +++++++++++++
15
.../tests/iothreads-commit-active.out | 23 +++++
18
tests/qemu-iotests/group | 1 +
16
2 files changed, 108 insertions(+)
19
3 files changed, 77 insertions(+)
17
create mode 100755 tests/qemu-iotests/tests/iothreads-commit-active
20
create mode 100755 tests/qemu-iotests/221
18
create mode 100644 tests/qemu-iotests/tests/iothreads-commit-active.out
21
create mode 100644 tests/qemu-iotests/221.out
22
19
23
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
20
diff --git a/tests/qemu-iotests/tests/iothreads-commit-active b/tests/qemu-iotests/tests/iothreads-commit-active
24
new file mode 100755
21
new file mode 100755
25
index XXXXXXX..XXXXXXX
22
index XXXXXXX..XXXXXXX
26
--- /dev/null
23
--- /dev/null
27
+++ b/tests/qemu-iotests/221
24
+++ b/tests/qemu-iotests/tests/iothreads-commit-active
28
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@
29
+#!/bin/bash
26
+#!/usr/bin/env python3
27
+# group: rw quick auto
30
+#
28
+#
31
+# Test qemu-img vs. unaligned images
29
+# Copyright (C) 2023 Red Hat, Inc.
32
+#
33
+# Copyright (C) 2018 Red Hat, Inc.
34
+#
30
+#
35
+# This program is free software; you can redistribute it and/or modify
31
+# 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
32
+# 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
33
+# the Free Software Foundation; either version 2 of the License, or
38
+# (at your option) any later version.
34
+# (at your option) any later version.
...
...
43
+# GNU General Public License for more details.
39
+# GNU General Public License for more details.
44
+#
40
+#
45
+# You should have received a copy of the GNU General Public License
41
+# 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/>.
42
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
47
+#
43
+#
44
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
48
+
45
+
49
+seq="$(basename $0)"
46
+import asyncio
50
+echo "QA output created by $seq"
47
+import iotests
51
+
48
+
52
+here="$PWD"
49
+iotests.script_initialize(supported_fmts=['qcow2'],
53
+status=1 # failure is the default!
50
+ supported_platforms=['linux'])
51
+iotests.verify_virtio_scsi_pci_or_ccw()
54
+
52
+
55
+_cleanup()
53
+with iotests.FilePath('disk0.img') as img_path, \
56
+{
54
+ iotests.FilePath('disk0-snap.img') as snap_path, \
57
+ _cleanup_test_img
55
+ iotests.FilePath('mirror-src.img') as src_path, \
58
+}
56
+ iotests.FilePath('mirror-dst.img') as dst_path, \
59
+trap "_cleanup; exit \$status" 0 1 2 3 15
57
+ iotests.VM() as vm:
60
+
58
+
61
+# get standard environment, filters and checks
59
+ img_size = '10M'
62
+. ./common.rc
60
+ iotests.qemu_img_create('-f', iotests.imgfmt, img_path, img_size)
63
+. ./common.filter
61
+ iotests.qemu_img_create('-f', iotests.imgfmt, '-b', img_path,
62
+ '-F', iotests.imgfmt, snap_path)
63
+ iotests.qemu_img_create('-f', iotests.imgfmt, src_path, img_size)
64
+ iotests.qemu_img_create('-f', iotests.imgfmt, dst_path, img_size)
64
+
65
+
65
+_supported_fmt raw
66
+ iotests.qemu_io_log('-c', 'write 0 64k', img_path)
66
+_supported_proto file
67
+ iotests.qemu_io_log('-c', 'write 1M 64k', snap_path)
67
+_supported_os Linux
68
+ iotests.qemu_io_log('-c', 'write 3M 64k', snap_path)
68
+
69
+
69
+echo
70
+ iotests.qemu_io_log('-c', f'write 0 {img_size}', src_path)
70
+echo "=== Check mapping of unaligned raw image ==="
71
+echo
72
+
71
+
73
+_make_test_img 43009 # qemu-img create rounds size up
72
+ iotests.log('Launching VM...')
74
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
73
+ vm.add_object('iothread,id=iothread0')
74
+ vm.add_object('throttle-group,x-bps-write=1048576,id=tg0')
75
+ vm.add_blockdev(f'file,node-name=disk0-file,filename={img_path}')
76
+ vm.add_blockdev('qcow2,node-name=disk0-fmt,file=disk0-file')
77
+ vm.add_drive(snap_path, 'backing=disk0-fmt,node-name=disk0',
78
+ interface='none')
79
+ vm.add_device('virtio-scsi,iothread=iothread0')
80
+ vm.add_device('scsi-hd,drive=drive0')
75
+
81
+
76
+truncate --size=43009 "$TEST_IMG" # so we resize it and check again
82
+ vm.add_blockdev(f'file,filename={src_path},node-name=mirror-src-file')
77
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
83
+ vm.add_blockdev('qcow2,file=mirror-src-file,node-name=mirror-src')
84
+ vm.add_blockdev(f'file,filename={dst_path},node-name=mirror-dst-file')
85
+ vm.add_blockdev('qcow2,file=mirror-dst-file,node-name=mirror-dst-fmt')
86
+ vm.add_blockdev('throttle,throttle-group=tg0,file=mirror-dst-fmt,'
87
+ 'node-name=mirror-dst')
88
+ vm.add_device('scsi-hd,drive=mirror-src')
78
+
89
+
79
+$QEMU_IO -c 'w 43008 1' "$TEST_IMG" | _filter_qemu_io # writing also rounds up
90
+ vm.launch()
80
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
81
+
91
+
82
+truncate --size=43009 "$TEST_IMG" # so we resize it and check again
92
+ # The background I/O is created on unrelated nodes (so that they won't be
83
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
93
+ # drained together with the other ones), but on the same iothread
94
+ iotests.log('Creating some background I/O...')
95
+ iotests.log(vm.qmp('blockdev-mirror', job_id='job0', sync='full',
96
+ device='mirror-src', target='mirror-dst',
97
+ auto_dismiss=False))
84
+
98
+
85
+# success, all done
99
+ iotests.log('Starting active commit...')
86
+echo '*** done'
100
+ iotests.log(vm.qmp('block-commit', device='disk0', job_id='job1',
87
+rm -f $seq.full
101
+ auto_dismiss=False))
88
+status=0
102
+
89
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
103
+ # Should succeed and not time out
104
+ try:
105
+ vm.run_job('job1', wait=5.0)
106
+ vm.shutdown()
107
+ except asyncio.TimeoutError:
108
+ # VM may be stuck, kill it
109
+ vm.kill()
110
+ raise
111
diff --git a/tests/qemu-iotests/tests/iothreads-commit-active.out b/tests/qemu-iotests/tests/iothreads-commit-active.out
90
new file mode 100644
112
new file mode 100644
91
index XXXXXXX..XXXXXXX
113
index XXXXXXX..XXXXXXX
92
--- /dev/null
114
--- /dev/null
93
+++ b/tests/qemu-iotests/221.out
115
+++ b/tests/qemu-iotests/tests/iothreads-commit-active.out
94
@@ -XXX,XX +XXX,XX @@
116
@@ -XXX,XX +XXX,XX @@
95
+QA output created by 221
117
+wrote 65536/65536 bytes at offset 0
118
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
96
+
119
+
97
+=== Check mapping of unaligned raw image ===
120
+wrote 65536/65536 bytes at offset 1048576
121
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
98
+
122
+
99
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=43009
123
+wrote 65536/65536 bytes at offset 3145728
100
+[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
124
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
101
+[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
125
+
102
+wrote 1/1 bytes at offset 43008
126
+wrote 10485760/10485760 bytes at offset 0
103
+1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
127
+10 MiB, 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},
128
+
105
+{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
129
+Launching VM...
106
+{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
130
+Creating some background I/O...
107
+[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
131
+{"return": {}}
108
+{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
132
+Starting active commit...
109
+{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
133
+{"return": {}}
110
+*** done
134
+{"execute": "job-complete", "arguments": {"id": "job1"}}
111
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
135
+{"return": {}}
112
index XXXXXXX..XXXXXXX 100644
136
+{"data": {"device": "job1", "len": 131072, "offset": 131072, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
113
--- a/tests/qemu-iotests/group
137
+{"data": {"device": "job1", "len": 131072, "offset": 131072, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
114
+++ b/tests/qemu-iotests/group
138
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
115
@@ -XXX,XX +XXX,XX @@
139
+{"return": {}}
116
217 rw auto quick
117
218 rw auto quick
118
219 rw auto
119
+221 rw auto quick
120
--
140
--
121
2.13.6
141
2.41.0
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
1
We removed all options from the 'deprecated' array, so the code is dead
1
blk_insert_bs() requires that callers hold the AioContext lock for the
2
and can be removed as well.
2
node that should be inserted. Take it.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
5
Message-ID: <20230605085711.21261-3-kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
8
---
7
blockdev.c | 12 ------------
9
hw/core/qdev-properties-system.c | 8 ++++++--
8
1 file changed, 12 deletions(-)
10
1 file changed, 6 insertions(+), 2 deletions(-)
9
11
10
diff --git a/blockdev.c b/blockdev.c
12
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
11
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
12
--- a/blockdev.c
14
--- a/hw/core/qdev-properties-system.c
13
+++ b/blockdev.c
15
+++ b/hw/core/qdev-properties-system.c
14
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
16
@@ -XXX,XX +XXX,XX @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name,
15
const char *filename;
17
* aware of iothreads require their BlockBackends to be in the main
16
Error *local_err = NULL;
18
* AioContext.
17
int i;
19
*/
18
- const char *deprecated[] = {
20
- ctx = iothread ? bdrv_get_aio_context(bs) : qemu_get_aio_context();
19
- };
21
- blk = blk_new(ctx, 0, BLK_PERM_ALL);
20
22
+ ctx = bdrv_get_aio_context(bs);
21
/* Change legacy command line options into QMP ones */
23
+ blk = blk_new(iothread ? ctx : qemu_get_aio_context(),
22
static const struct {
24
+ 0, BLK_PERM_ALL);
23
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
25
blk_created = true;
24
goto fail;
26
25
}
27
+ aio_context_acquire(ctx);
26
28
ret = blk_insert_bs(blk, bs, errp);
27
- /* Other deprecated options */
29
+ aio_context_release(ctx);
28
- if (!qtest_enabled()) {
30
+
29
- for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
31
if (ret < 0) {
30
- if (qemu_opt_get(legacy_opts, deprecated[i]) != NULL) {
32
goto fail;
31
- error_report("'%s' is deprecated, please use the corresponding "
33
}
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
--
34
--
41
2.13.6
35
2.41.0
42
43
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
blk_insert_bs() requires that callers hold the AioContext lock for the
2
node that should be inserted. Take it.
2
3
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Message-ID: <20230605085711.21261-4-kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
8
---
7
tests/check-block-qdict.c | 14 +++++++++++++-
9
tests/unit/test-block-iothread.c | 7 ++++++-
8
1 file changed, 13 insertions(+), 1 deletion(-)
10
1 file changed, 6 insertions(+), 1 deletion(-)
9
11
10
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
12
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
11
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/check-block-qdict.c
14
--- a/tests/unit/test-block-iothread.c
13
+++ b/tests/check-block-qdict.c
15
+++ b/tests/unit/test-block-iothread.c
14
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
16
@@ -XXX,XX +XXX,XX @@ static void test_attach_second_node(void)
15
QList *e = qlist_new();
17
BlockDriverState *bs, *filter;
16
QDict *e_1_2 = qdict_new();
18
QDict *options;
17
QDict *f = qdict_new();
19
18
+ QList *y = qlist_new();
20
+ aio_context_acquire(main_ctx);
19
+ QDict *z = qdict_new();
21
blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
20
QDict *root = qdict_new();
22
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
21
23
blk_insert_bs(blk, bs, &error_abort);
22
/*
24
@@ -XXX,XX +XXX,XX @@ static void test_attach_second_node(void)
23
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
25
qdict_put_str(options, "driver", "raw");
24
* "c": 2,
26
qdict_put_str(options, "file", "base");
25
* "d": 3,
27
26
* },
28
- aio_context_acquire(main_ctx);
27
- * "g": 4
29
filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
28
+ * "g": 4,
30
aio_context_release(main_ctx);
29
+ * "y": [{}],
31
30
+ * "z": {"a": []}
32
@@ -XXX,XX +XXX,XX @@ static void test_attach_preserve_blk_ctx(void)
31
* }
33
{
32
*
34
IOThread *iothread = iothread_new();
33
* to
35
AioContext *ctx = iothread_get_aio_context(iothread);
34
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
36
+ AioContext *main_ctx = qemu_get_aio_context();
35
* "f.d": 3,
37
BlockBackend *blk;
36
* "g": 4
38
BlockDriverState *bs;
37
* }
39
38
+ *
40
+ aio_context_acquire(main_ctx);
39
+ * Note that "y" and "z" get eaten.
41
blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
40
*/
42
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
41
43
bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
42
qdict_put_int(e_1_2, "a", 0);
44
@@ -XXX,XX +XXX,XX @@ static void test_attach_preserve_blk_ctx(void)
43
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
45
blk_insert_bs(blk, bs, &error_abort);
44
qdict_put_int(f, "c", 2);
46
g_assert(blk_get_aio_context(blk) == ctx);
45
qdict_put_int(f, "d", 3);
47
g_assert(bdrv_get_aio_context(bs) == ctx);
46
48
+ aio_context_release(main_ctx);
47
+ qlist_append(y, qdict_new());
49
48
+
50
/* Remove the node again */
49
+ qdict_put(z, "a", qlist_new());
51
aio_context_acquire(ctx);
50
+
52
@@ -XXX,XX +XXX,XX @@ static void test_attach_preserve_blk_ctx(void)
51
qdict_put(root, "e", e);
53
g_assert(bdrv_get_aio_context(bs) == qemu_get_aio_context());
52
qdict_put(root, "f", f);
54
53
qdict_put_int(root, "g", 4);
55
/* Re-attach the node */
54
+ qdict_put(root, "y", y);
56
+ aio_context_acquire(main_ctx);
55
+ qdict_put(root, "z", z);
57
blk_insert_bs(blk, bs, &error_abort);
56
58
+ aio_context_release(main_ctx);
57
qdict_flatten(root);
59
g_assert(blk_get_aio_context(blk) == ctx);
60
g_assert(bdrv_get_aio_context(bs) == ctx);
58
61
59
--
62
--
60
2.13.6
63
2.41.0
61
62
diff view generated by jsdifflib
1
The -drive option addr was deprecated in QEMU 2.10. It's time to remove
1
bdrv_attach_child() requires that the caller holds the AioContext lock
2
it.
2
for the new child node. Take it in bdrv_open_child() and document that
3
the caller must not hold any AioContext apart from the main AioContext.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
Message-ID: <20230605085711.21261-5-kwolf@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
9
---
8
include/sysemu/blockdev.h | 1 -
10
block.c | 13 +++++++++++--
9
blockdev.c | 17 +----------------
11
1 file changed, 11 insertions(+), 2 deletions(-)
10
device-hotplug.c | 4 ----
11
qemu-doc.texi | 5 -----
12
qemu-options.hx | 5 +----
13
5 files changed, 2 insertions(+), 30 deletions(-)
14
12
15
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
13
diff --git a/block.c b/block.c
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/include/sysemu/blockdev.h
15
--- a/block.c
18
+++ b/include/sysemu/blockdev.h
16
+++ b/block.c
19
@@ -XXX,XX +XXX,XX @@ typedef enum {
17
@@ -XXX,XX +XXX,XX @@ done:
20
} BlockInterfaceType;
18
*
21
19
* The BlockdevRef will be removed from the options QDict.
22
struct DriveInfo {
20
*
23
- const char *devaddr;
21
+ * The caller must hold the lock of the main AioContext and no other AioContext.
24
BlockInterfaceType type;
22
* @parent can move to a different AioContext in this function. Callers must
25
int bus;
23
* make sure that their AioContext locking is still correct after this.
26
int unit;
24
*/
27
diff --git a/blockdev.c b/blockdev.c
25
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
28
index XXXXXXX..XXXXXXX 100644
26
bool allow_none, Error **errp)
29
--- a/blockdev.c
27
{
30
+++ b/blockdev.c
28
BlockDriverState *bs;
31
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
29
+ BdrvChild *child;
32
.type = QEMU_OPT_STRING,
30
+ AioContext *ctx;
33
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
31
34
},{
32
GLOBAL_STATE_CODE();
35
- .name = "addr",
33
36
- .type = QEMU_OPT_STRING,
34
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
37
- .help = "pci address (virtio only)",
35
return NULL;
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
}
36
}
61
37
62
/* Add virtio block device */
38
- return bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
63
- devaddr = qemu_opt_get(legacy_opts, "addr");
39
- errp);
64
- if (devaddr && type != IF_VIRTIO) {
40
+ ctx = bdrv_get_aio_context(bs);
65
- error_report("addr is not supported by this bus type");
41
+ aio_context_acquire(ctx);
66
- goto fail;
42
+ child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
67
- }
43
+ errp);
68
-
44
+ aio_context_release(ctx);
69
if (type == IF_VIRTIO) {
45
+
70
QemuOpts *devopts;
46
+ return child;
71
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
47
}
72
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
48
73
}
49
/*
74
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
50
* Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
75
&error_abort);
51
*
76
- if (devaddr) {
52
+ * The caller must hold the lock of the main AioContext and no other AioContext.
77
- qemu_opt_set(devopts, "addr", devaddr, &error_abort);
53
* @parent can move to a different AioContext in this function. Callers must
78
- }
54
* make sure that their AioContext locking is still correct after this.
79
}
55
*/
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
--
56
--
145
2.13.6
57
2.41.0
146
147
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
The function can move the child node to a different AioContext. In this
2
case, it also must take the AioContext lock for the new context before
3
calling functions that require the caller to hold the AioContext for the
4
child node.
2
5
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Message-ID: <20230605085711.21261-6-kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
10
---
7
qobject/block-qdict.c | 27 +++++++++++----------------
11
block.c | 21 ++++++++++++++++++++-
8
1 file changed, 11 insertions(+), 16 deletions(-)
12
1 file changed, 20 insertions(+), 1 deletion(-)
9
13
10
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
14
diff --git a/block.c b/block.c
11
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
12
--- a/qobject/block-qdict.c
16
--- a/block.c
13
+++ b/qobject/block-qdict.c
17
+++ b/block.c
14
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
18
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_attach_child_common_drv = {
15
19
* Function doesn't update permissions, caller is responsible for this.
16
for (ent = qdict_first(maybe_list); ent != NULL;
20
*
17
ent = qdict_next(maybe_list, ent)) {
21
* Returns new created child.
18
+ int is_index = !qemu_strtoi64(ent->key, NULL, 10, &val);
22
+ *
19
23
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
20
- if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
24
+ * @child_bs can move to a different AioContext in this function. Callers must
21
- if (is_list == -1) {
25
+ * make sure that their AioContext locking is still correct after this.
22
- is_list = 1;
26
*/
23
- } else if (!is_list) {
27
static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
24
- error_setg(errp,
28
const char *child_name,
25
- "Cannot mix list and non-list keys");
29
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
26
- return -1;
30
Transaction *tran, Error **errp)
27
- }
31
{
28
+ if (is_list == -1) {
32
BdrvChild *new_child;
29
+ is_list = is_index;
33
- AioContext *parent_ctx;
30
+ }
34
+ AioContext *parent_ctx, *new_child_ctx;
31
+
35
AioContext *child_ctx = bdrv_get_aio_context(child_bs);
32
+ if (is_index != is_list) {
36
33
+ error_setg(errp, "Cannot mix list and non-list keys");
37
assert(child_class->get_parent_desc);
34
+ return -1;
38
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
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
}
39
}
51
}
40
}
52
41
42
+ new_child_ctx = bdrv_get_aio_context(child_bs);
43
+ if (new_child_ctx != child_ctx) {
44
+ aio_context_release(child_ctx);
45
+ aio_context_acquire(new_child_ctx);
46
+ }
47
+
48
bdrv_ref(child_bs);
49
/*
50
* Let every new BdrvChild start with a drained parent. Inserting the child
51
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
52
};
53
tran_add(tran, &bdrv_attach_child_common_drv, s);
54
55
+ if (new_child_ctx != child_ctx) {
56
+ aio_context_release(new_child_ctx);
57
+ aio_context_acquire(child_ctx);
58
+ }
59
+
60
return new_child;
61
}
62
63
/*
64
* Function doesn't update permissions, caller is responsible for this.
65
+ *
66
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
67
+ * @child_bs can move to a different AioContext in this function. Callers must
68
+ * make sure that their AioContext locking is still correct after this.
69
*/
70
static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs,
71
BlockDriverState *child_bs,
53
--
72
--
54
2.13.6
73
2.41.0
55
56
diff view generated by jsdifflib
1
The -drive options cyls, heads, secs and trans were deprecated in
1
bdrv_set_file_or_backing_noperm() requires the caller to hold the
2
QEMU 2.10. It's time to remove them.
2
AioContext lock for the child node, but we hold the one for the parent
3
3
node in bdrv_reopen_parse_file_or_backing(). Take the other one
4
hd-geo-test tested both the old version with geometry options in -drive
4
temporarily.
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
5
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Markus Armbruster <armbru@redhat.com>
7
Message-ID: <20230605085711.21261-7-kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
10
---
12
include/sysemu/blockdev.h | 1 -
11
block.c | 35 +++++++++++++++++++++++++++++++++--
13
blockdev.c | 75 +----------------------------------------------
12
1 file changed, 33 insertions(+), 2 deletions(-)
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
13
21
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
14
diff --git a/block.c b/block.c
22
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
23
--- a/include/sysemu/blockdev.h
16
--- a/block.c
24
+++ b/include/sysemu/blockdev.h
17
+++ b/block.c
25
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
18
@@ -XXX,XX +XXX,XX @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs)
26
int auto_del; /* see blockdev_mark_auto_del() */
19
* callers which don't need their own reference any more must call bdrv_unref().
27
bool is_default; /* Added by default_drive() ? */
20
*
28
int media_cd;
21
* Function doesn't update permissions, caller is responsible for this.
29
- int cyls, heads, secs, trans;
22
+ *
30
QemuOpts *opts;
23
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
31
char *serial;
24
+ * @child_bs can move to a different AioContext in this function. Callers must
32
QTAILQ_ENTRY(DriveInfo) next;
25
+ * make sure that their AioContext locking is still correct after this.
33
diff --git a/blockdev.c b/blockdev.c
26
*/
34
index XXXXXXX..XXXXXXX 100644
27
static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
35
--- a/blockdev.c
28
BlockDriverState *child_bs,
36
+++ b/blockdev.c
29
@@ -XXX,XX +XXX,XX @@ out:
37
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
30
return 0;
38
.type = QEMU_OPT_STRING,
31
}
39
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
32
40
},{
33
+/*
41
- .name = "cyls",
34
+ * The caller must hold the AioContext lock for @backing_hd. Both @bs and
42
- .type = QEMU_OPT_NUMBER,
35
+ * @backing_hd can move to a different AioContext in this function. Callers must
43
- .help = "number of cylinders (ide disk geometry)",
36
+ * make sure that their AioContext locking is still correct after this.
44
- },{
37
+ */
45
- .name = "heads",
38
static int bdrv_set_backing_noperm(BlockDriverState *bs,
46
- .type = QEMU_OPT_NUMBER,
39
BlockDriverState *backing_hd,
47
- .help = "number of heads (ide disk geometry)",
40
Transaction *tran, Error **errp)
48
- },{
41
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
49
- .name = "secs",
42
* backing BlockDriverState (or NULL).
50
- .type = QEMU_OPT_NUMBER,
43
*
51
- .help = "number of sectors (ide disk geometry)",
44
* Return 0 on success, otherwise return < 0 and set @errp.
52
- },{
45
+ *
53
- .name = "trans",
46
+ * The caller must hold the AioContext lock of @reopen_state->bs.
54
- .type = QEMU_OPT_STRING,
47
+ * @reopen_state->bs can move to a different AioContext in this function.
55
- .help = "chs translation (auto, lba, none)",
48
+ * Callers must make sure that their AioContext locking is still correct after
56
- },{
49
+ * this.
57
.name = "addr",
50
*/
58
.type = QEMU_OPT_STRING,
51
static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
59
.help = "pci address (virtio only)",
52
bool is_backing, Transaction *tran,
60
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
53
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
61
QemuOpts *legacy_opts;
54
const char *child_name = is_backing ? "backing" : "file";
62
DriveMediaType media = MEDIA_DISK;
55
QObject *value;
63
BlockInterfaceType type;
56
const char *str;
64
- int cyls, heads, secs, translation;
57
+ AioContext *ctx, *old_ctx;
65
int max_devs, bus_id, unit_id, index;
58
+ int ret;
66
const char *devaddr;
59
67
const char *werror, *rerror;
60
GLOBAL_STATE_CODE();
68
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
61
69
Error *local_err = NULL;
62
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
70
int i;
63
reopen_state->old_file_bs = old_child_bs;
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
}
64
}
80
65
81
- /* Geometry */
66
- return bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
82
- cyls = qemu_opt_get_number(legacy_opts, "cyls", 0);
67
- tran, errp);
83
- heads = qemu_opt_get_number(legacy_opts, "heads", 0);
68
+ old_ctx = bdrv_get_aio_context(bs);
84
- secs = qemu_opt_get_number(legacy_opts, "secs", 0);
69
+ ctx = bdrv_get_aio_context(new_child_bs);
85
-
70
+ if (old_ctx != ctx) {
86
- if (cyls || heads || secs) {
71
+ aio_context_release(old_ctx);
87
- if (cyls < 1) {
72
+ aio_context_acquire(ctx);
88
- error_report("invalid physical cyls number");
73
+ }
89
- goto fail;
74
+
90
- }
75
+ ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
91
- if (heads < 1) {
76
+ tran, errp);
92
- error_report("invalid physical heads number");
77
+
93
- goto fail;
78
+ if (old_ctx != ctx) {
94
- }
79
+ aio_context_release(ctx);
95
- if (secs < 1) {
80
+ aio_context_acquire(old_ctx);
96
- error_report("invalid physical secs number");
81
+ }
97
- goto fail;
82
+
98
- }
83
+ return ret;
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
}
84
}
225
85
226
/*
86
/*
227
- * Test case: IDE device (if=ide) with explicit CHS
87
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
228
- */
88
* It is the responsibility of the caller to then call the abort() or
229
-static void test_ide_drive_user_chs(void)
89
* commit() for any other BDS that have been left in a prepare() state
230
-{
90
*
231
- test_ide_drive_user(NULL, false);
91
+ * The caller must hold the AioContext lock of @reopen_state->bs.
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
*/
92
*/
245
static void test_ide_device_user_chs(void)
93
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
246
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_cd_0(void)
94
BlockReopenQueue *queue,
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
--
95
--
320
2.13.6
96
2.41.0
321
322
diff view generated by jsdifflib
1
The -drive option serial was deprecated in QEMU 2.10. It's time to
1
bdrv_open_inherit() calls several functions for which it needs to hold
2
remove it.
2
the AioContext lock, but currently doesn't. This includes calls in
3
3
bdrv_append_temp_snapshot(), for which bdrv_open_inherit() is the only
4
Tests need to be updated to set the serial number with -global instead
4
caller. Fix the locking in these places.
5
of using the -drive option.
6
5
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Markus Armbruster <armbru@redhat.com>
7
Message-ID: <20230605085711.21261-8-kwolf@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
10
---
11
include/hw/block/block.h | 1 -
11
block.c | 25 ++++++++++++++++++++++++-
12
include/sysemu/blockdev.h | 1 -
12
1 file changed, 24 insertions(+), 1 deletion(-)
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
13
27
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
14
diff --git a/block.c b/block.c
28
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
29
--- a/include/hw/block/block.h
16
--- a/block.c
30
+++ b/include/hw/block/block.h
17
+++ b/block.c
31
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
18
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
32
19
int64_t total_size;
33
/* Configuration helpers */
20
QemuOpts *opts = NULL;
34
21
BlockDriverState *bs_snapshot = NULL;
35
-void blkconf_serial(BlockConf *conf, char **serial);
22
+ AioContext *ctx = bdrv_get_aio_context(bs);
36
bool blkconf_geometry(BlockConf *conf, int *trans,
23
int ret;
37
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
24
38
Error **errp);
25
GLOBAL_STATE_CODE();
39
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
26
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
40
index XXXXXXX..XXXXXXX 100644
27
instead of opening 'filename' directly */
41
--- a/include/sysemu/blockdev.h
28
42
+++ b/include/sysemu/blockdev.h
29
/* Get the required size from the image */
43
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
30
+ aio_context_acquire(ctx);
44
bool is_default; /* Added by default_drive() ? */
31
total_size = bdrv_getlength(bs);
45
int media_cd;
32
+ aio_context_release(ctx);
46
QemuOpts *opts;
33
+
47
- char *serial;
34
if (total_size < 0) {
48
QTAILQ_ENTRY(DriveInfo) next;
35
error_setg_errno(errp, -total_size, "Could not get image size");
49
};
36
goto out;
50
37
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
51
diff --git a/block/block-backend.c b/block/block-backend.c
38
goto out;
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
}
39
}
58
qemu_opts_del(dinfo->opts);
40
59
- g_free(dinfo->serial);
41
+ aio_context_acquire(ctx);
60
g_free(dinfo);
42
ret = bdrv_append(bs_snapshot, bs, errp);
61
}
43
+ aio_context_release(ctx);
62
44
+
63
diff --git a/blockdev.c b/blockdev.c
45
if (ret < 0) {
64
index XXXXXXX..XXXXXXX 100644
46
bs_snapshot = NULL;
65
--- a/blockdev.c
47
goto out;
66
+++ b/blockdev.c
48
@@ -XXX,XX +XXX,XX @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
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;
49
Error *local_err = NULL;
85
int i;
50
QDict *snapshot_options = NULL;
86
const char *deprecated[] = {
51
int snapshot_flags = 0;
87
- "serial"
52
+ AioContext *ctx = qemu_get_aio_context();
88
};
53
89
54
assert(!child_class || !flags);
90
/* Change legacy command line options into QMP ones */
55
assert(!child_class == !parent);
91
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
56
@@ -XXX,XX +XXX,XX @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
57
/* Not requesting BLK_PERM_CONSISTENT_READ because we're only
58
* looking at the header to guess the image format. This works even
59
* in cases where a guest would not see a consistent state. */
60
- file = blk_new(bdrv_get_aio_context(file_bs), 0, BLK_PERM_ALL);
61
+ ctx = bdrv_get_aio_context(file_bs);
62
+ aio_context_acquire(ctx);
63
+ file = blk_new(ctx, 0, BLK_PERM_ALL);
64
blk_insert_bs(file, file_bs, &local_err);
65
bdrv_unref(file_bs);
66
+ aio_context_release(ctx);
67
+
68
if (local_err) {
69
goto fail;
70
}
71
@@ -XXX,XX +XXX,XX @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
92
goto fail;
72
goto fail;
93
}
73
}
94
74
95
- /* Serial number */
75
+ /* The AioContext could have changed during bdrv_open_common() */
96
- serial = qemu_opt_get(legacy_opts, "serial");
76
+ ctx = bdrv_get_aio_context(bs);
97
-
77
+
98
/* no id supplied -> create one */
78
if (file) {
99
if (qemu_opts_id(all_opts) == NULL) {
79
+ aio_context_acquire(ctx);
100
char *new_id;
80
blk_unref(file);
101
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
81
+ aio_context_release(ctx);
102
dinfo->type = type;
82
file = NULL;
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
}
83
}
140
84
141
- blkconf_serial(&n->conf, &n->serial);
85
@@ -XXX,XX +XXX,XX @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
142
if (!n->serial) {
86
* (snapshot_bs); thus, we have to drop the strong reference to bs
143
error_setg(errp, "serial property not set");
87
* (which we obtained by calling bdrv_new()). bs will not be deleted,
144
return;
88
* though, because the overlay still has a reference to it. */
145
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
89
+ aio_context_acquire(ctx);
146
index XXXXXXX..XXXXXXX 100644
90
bdrv_unref(bs);
147
--- a/hw/block/virtio-blk.c
91
+ aio_context_release(ctx);
148
+++ b/hw/block/virtio-blk.c
92
bs = snapshot_bs;
149
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
150
return;
151
}
93
}
152
94
153
- blkconf_serial(&conf->conf, &conf->serial);
95
return bs;
154
if (!blkconf_apply_backend_options(&conf->conf,
96
155
blk_is_read_only(conf->conf.blk), true,
97
fail:
156
errp)) {
98
+ aio_context_acquire(ctx);
157
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
99
blk_unref(file);
158
index XXXXXXX..XXXXXXX 100644
100
qobject_unref(snapshot_options);
159
--- a/hw/ide/qdev.c
101
qobject_unref(bs->explicit_options);
160
+++ b/hw/ide/qdev.c
102
@@ -XXX,XX +XXX,XX @@ fail:
161
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
103
bs->options = NULL;
162
return;
104
bs->explicit_options = NULL;
163
}
105
bdrv_unref(bs);
164
106
+ aio_context_release(ctx);
165
- blkconf_serial(&dev->conf, &dev->serial);
107
error_propagate(errp, local_err);
166
if (kind != IDE_CD) {
108
return NULL;
167
if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
109
168
errp)) {
110
close_and_fail:
169
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
111
+ aio_context_acquire(ctx);
170
index XXXXXXX..XXXXXXX 100644
112
bdrv_unref(bs);
171
--- a/hw/scsi/scsi-disk.c
113
+ aio_context_release(ctx);
172
+++ b/hw/scsi/scsi-disk.c
114
qobject_unref(snapshot_options);
173
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
115
qobject_unref(options);
174
return;
116
error_propagate(errp, local_err);
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
--
117
--
280
2.13.6
118
2.41.0
281
282
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
bdrv_set_backing() requires the caller to hold the AioContext lock for
2
@backing_hd. Take it in bdrv_open_backing_file() before calling the
3
function.
2
4
3
When you mix scalar and non-scalar keys, whether you get an "already
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
set as scalar" or an "already set as dict" error depends on qdict
6
Message-ID: <20230605085711.21261-9-kwolf@redhat.com>
5
iteration order. Neither message makes much sense. Replace by
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
9
---
15
qobject/block-qdict.c | 32 ++++++++++++++++----------------
10
block.c | 5 +++++
16
1 file changed, 16 insertions(+), 16 deletions(-)
11
1 file changed, 5 insertions(+)
17
12
18
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
13
diff --git a/block.c b/block.c
19
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
20
--- a/qobject/block-qdict.c
15
--- a/block.c
21
+++ b/qobject/block-qdict.c
16
+++ b/block.c
22
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
17
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
23
QObject *qdict_crumple(const QDict *src, Error **errp)
18
int ret = 0;
24
{
19
bool implicit_backing = false;
25
const QDictEntry *ent;
20
BlockDriverState *backing_hd;
26
- QDict *two_level, *multi_level = NULL;
21
+ AioContext *backing_hd_ctx;
27
+ QDict *two_level, *multi_level = NULL, *child_dict;
22
QDict *options;
28
QObject *dst = NULL, *child;
23
QDict *tmp_parent_options = NULL;
29
size_t i;
24
Error *local_err = NULL;
30
char *prefix = NULL;
25
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
31
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
26
32
}
27
/* Hook up the backing file link; drop our reference, bs owns the
33
28
* backing_hd reference now */
34
qdict_split_flat_key(ent->key, &prefix, &suffix);
29
+ backing_hd_ctx = bdrv_get_aio_context(backing_hd);
35
-
30
+ aio_context_acquire(backing_hd_ctx);
36
child = qdict_get(two_level, prefix);
31
ret = bdrv_set_backing_hd(bs, backing_hd, errp);
37
+ child_dict = qobject_to(QDict, child);
32
bdrv_unref(backing_hd);
33
+ aio_context_release(backing_hd_ctx);
38
+
34
+
39
+ if (child) {
35
if (ret < 0) {
40
+ /*
36
goto free_exit;
41
+ * If @child_dict, then all previous keys with this prefix
37
}
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
--
38
--
76
2.13.6
39
2.41.0
77
78
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
bdrv_root_attach_child() requires callers to hold the AioContext lock
2
for child_bs. Take it in block_job_add_bdrv() before calling the
3
function.
2
4
3
qdict_flatten_qdict() skips copying scalars from @qdict to @target
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
when the two are the same. Fair enough, but it uses a non-obvious
6
Message-ID: <20230605085711.21261-10-kwolf@redhat.com>
5
test for "same". Replace it by the obvious one. While there, improve
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
9
---
12
qobject/block-qdict.c | 14 +++++++++-----
10
blockjob.c | 17 ++++++++++++-----
13
1 file changed, 9 insertions(+), 5 deletions(-)
11
1 file changed, 12 insertions(+), 5 deletions(-)
14
12
15
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
13
diff --git a/blockjob.c b/blockjob.c
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/qobject/block-qdict.c
15
--- a/blockjob.c
18
+++ b/qobject/block-qdict.c
16
+++ b/blockjob.c
19
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
17
@@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
20
value = qlist_entry_obj(entry);
18
uint64_t perm, uint64_t shared_perm, Error **errp)
21
new_key = g_strdup_printf("%s.%i", prefix, i);
19
{
22
20
BdrvChild *c;
23
+ /*
21
+ AioContext *ctx = bdrv_get_aio_context(bs);
24
+ * Flatten non-empty QDict and QList recursively into @target,
22
bool need_context_ops;
25
+ * copy other objects to @target
23
GLOBAL_STATE_CODE();
26
+ */
24
27
if (qobject_type(value) == QTYPE_QDICT) {
25
bdrv_ref(bs);
28
qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
26
29
} else if (qobject_type(value) == QTYPE_QLIST) {
27
- need_context_ops = bdrv_get_aio_context(bs) != job->job.aio_context;
30
qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
28
+ need_context_ops = ctx != job->job.aio_context;
31
} else {
29
32
- /* All other types are moved to the target unchanged. */
30
- if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) {
33
qdict_put_obj(target, new_key, qobject_ref(value));
31
- aio_context_release(job->job.aio_context);
34
}
32
+ if (need_context_ops) {
35
33
+ if (job->job.aio_context != qemu_get_aio_context()) {
36
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
34
+ aio_context_release(job->job.aio_context);
37
new_key = g_strdup_printf("%s.%s", prefix, entry->key);
35
+ }
38
}
36
+ aio_context_acquire(ctx);
39
37
}
40
+ /*
38
c = bdrv_root_attach_child(bs, name, &child_job, 0, perm, shared_perm, job,
41
+ * Flatten non-empty QDict and QList recursively into @target,
39
errp);
42
+ * copy other objects to @target
40
- if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) {
43
+ */
41
- aio_context_acquire(job->job.aio_context);
44
if (qobject_type(value) == QTYPE_QDICT) {
42
+ if (need_context_ops) {
45
- /* Entries of QDicts are processed recursively, the QDict object
43
+ aio_context_release(ctx);
46
- * itself disappears. */
44
+ if (job->job.aio_context != qemu_get_aio_context()) {
47
qdict_flatten_qdict(qobject_to(QDict, value), target,
45
+ aio_context_acquire(job->job.aio_context);
48
new_key ? new_key : entry->key);
46
+ }
49
qdict_del(qdict, entry->key);
47
}
50
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
48
if (c == NULL) {
51
qdict_flatten_qlist(qobject_to(QList, value), target,
49
return -EPERM;
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
--
50
--
61
2.13.6
51
2.41.0
62
63
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
If the caller keeps the AioContext lock for a block node in an iothread,
2
polling in bdrv_graph_wrlock() deadlocks if the condition isn't
3
fulfilled immediately.
2
4
3
Parameter auth-client-required lets you configure authentication
5
Now that all callers make sure to actually have the AioContext locked
4
methods. We tried to provide that in v2.9.0, but backed out due to
6
when they call bdrv_replace_child_noperm() like they should, we can
5
interface design doubts (commit 464444fcc16).
7
change bdrv_graph_wrlock() to take a BlockDriverState whose AioContext
8
lock the caller holds (NULL if it doesn't) and unlock it temporarily
9
while polling.
6
10
7
This commit is similar to what we backed out, but simpler: we use a
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
list of enumeration values instead of a list of objects with a member
12
Message-ID: <20230605085711.21261-11-kwolf@redhat.com>
9
of enumeration type.
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
63
---
15
---
64
qapi/block-core.json | 13 +++++++++++++
16
include/block/graph-lock.h | 6 ++++--
65
block/rbd.c | 42 ++++++++++++++++++++++++++++++++----------
17
block.c | 4 ++--
66
2 files changed, 45 insertions(+), 10 deletions(-)
18
block/graph-lock.c | 23 ++++++++++++++++++++++-
19
3 files changed, 28 insertions(+), 5 deletions(-)
67
20
68
diff --git a/qapi/block-core.json b/qapi/block-core.json
21
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
69
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
70
--- a/qapi/block-core.json
23
--- a/include/block/graph-lock.h
71
+++ b/qapi/block-core.json
24
+++ b/include/block/graph-lock.h
72
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@ void unregister_aiocontext(AioContext *ctx);
73
26
* The wrlock can only be taken from the main loop, with BQL held, as only the
74
27
* main loop is allowed to modify the graph.
75
##
28
*
76
+# @RbdAuthMode:
29
+ * If @bs is non-NULL, its AioContext is temporarily released.
77
+#
30
+ *
78
+# Since: 3.0
31
* This function polls. Callers must not hold the lock of any AioContext other
79
+##
32
- * than the current one.
80
+{ 'enum': 'RbdAuthMode',
33
+ * than the current one and the one of @bs.
81
+ 'data': [ 'cephx', 'none' ] }
34
*/
35
-void bdrv_graph_wrlock(void) TSA_ACQUIRE(graph_lock) TSA_NO_TSA;
36
+void bdrv_graph_wrlock(BlockDriverState *bs) TSA_ACQUIRE(graph_lock) TSA_NO_TSA;
37
38
/*
39
* bdrv_graph_wrunlock:
40
diff --git a/block.c b/block.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/block.c
43
+++ b/block.c
44
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
45
* Replaces the node that a BdrvChild points to without updating permissions.
46
*
47
* If @new_bs is non-NULL, the parent of @child must already be drained through
48
- * @child.
49
+ * @child and the caller must hold the AioContext lock for @new_bs.
50
*/
51
static void bdrv_replace_child_noperm(BdrvChild *child,
52
BlockDriverState *new_bs)
53
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
54
}
55
56
/* TODO Pull this up into the callers to avoid polling here */
57
- bdrv_graph_wrlock();
58
+ bdrv_graph_wrlock(new_bs);
59
if (old_bs) {
60
if (child->klass->detach) {
61
child->klass->detach(child);
62
diff --git a/block/graph-lock.c b/block/graph-lock.c
63
index XXXXXXX..XXXXXXX 100644
64
--- a/block/graph-lock.c
65
+++ b/block/graph-lock.c
66
@@ -XXX,XX +XXX,XX @@ static uint32_t reader_count(void)
67
}
68
#endif
69
70
-void bdrv_graph_wrlock(void)
71
+void bdrv_graph_wrlock(BlockDriverState *bs)
72
{
73
+ AioContext *ctx = NULL;
82
+
74
+
83
+##
75
GLOBAL_STATE_CODE();
84
# @BlockdevOptionsRbd:
76
/*
85
#
77
* TODO Some callers hold an AioContext lock when this is called, which
86
# @pool: Ceph pool name.
78
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(void)
87
@@ -XXX,XX +XXX,XX @@
79
*/
88
#
80
#if 0
89
# @user: Ceph id name.
81
assert(!qatomic_read(&has_writer));
90
#
82
+#endif
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
+
83
+
125
+ if (secretid) {
84
+ /*
126
+ gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
85
+ * Release only non-mainloop AioContext. The mainloop often relies on the
127
+ errp);
86
+ * BQL and doesn't lock the main AioContext before doing things.
128
+ if (!secret) {
87
+ */
129
+ return -1;
88
+ if (bs) {
130
+ }
89
+ ctx = bdrv_get_aio_context(bs);
131
90
+ if (ctx != qemu_get_aio_context()) {
132
- gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
91
+ aio_context_release(ctx);
133
- errp);
92
+ } else {
134
- if (!secret) {
93
+ ctx = NULL;
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
+ }
94
+ }
158
+ }
95
+ }
159
96
160
return 0;
97
+#if 0
98
/* Make sure that constantly arriving new I/O doesn't cause starvation */
99
bdrv_drain_all_begin_nopoll();
100
101
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(void)
102
103
bdrv_drain_all_end();
104
#endif
105
+
106
+ if (ctx) {
107
+ aio_context_acquire(bdrv_get_aio_context(bs));
108
+ }
161
}
109
}
162
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
110
163
}
111
void bdrv_graph_wrunlock(void)
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
--
112
--
172
2.13.6
113
2.41.0
173
174
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
Now that bdrv_graph_wrlock() temporarily drops the AioContext lock that
2
its caller holds, it can poll without causing deadlocks. We can now
3
re-enable graph locking.
2
4
3
Legacy -drive supports "password-secret" parameter that isn't
5
This reverts commit ad128dff0bf4b6f971d05eb4335a627883a19c1d.
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
6
8
This is the second try. It brings back the parameter, except it's
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
named "key-secret" now.
8
Message-ID: <20230605085711.21261-12-kwolf@redhat.com>
10
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
---
11
---
35
qapi/block-core.json | 6 ++++++
12
block/graph-lock.c | 26 --------------------------
36
block/rbd.c | 41 +++++++++++++++++++++++++----------------
13
1 file changed, 26 deletions(-)
37
2 files changed, 31 insertions(+), 16 deletions(-)
38
14
39
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
diff --git a/block/graph-lock.c b/block/graph-lock.c
40
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
41
--- a/qapi/block-core.json
17
--- a/block/graph-lock.c
42
+++ b/qapi/block-core.json
18
+++ b/block/graph-lock.c
43
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ BdrvGraphLock graph_lock;
44
# This maps to Ceph configuration option
20
/* Protects the list of aiocontext and orphaned_reader_count */
45
# "auth_client_required". (Since 3.0)
21
static QemuMutex aio_context_list_lock;
46
#
22
47
+# @key-secret: ID of a QCryptoSecret object providing a key
23
-#if 0
48
+# for cephx authentication.
24
/* Written and read with atomic operations. */
49
+# This maps to Ceph configuration option
25
static int has_writer;
50
+# "key". (Since 3.0)
26
-#endif
51
+#
27
52
# @server: Monitor host address and port. This maps
28
/*
53
# to the "mon_host" Ceph option.
29
* A reader coroutine could move from an AioContext to another.
54
#
30
@@ -XXX,XX +XXX,XX @@ void unregister_aiocontext(AioContext *ctx)
55
@@ -XXX,XX +XXX,XX @@
31
g_free(ctx->bdrv_graph);
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
}
32
}
69
33
70
34
-#if 0
71
-static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
35
static uint32_t reader_count(void)
72
- BlockdevOptionsRbd *opts,
73
+static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts,
74
Error **errp)
75
{
36
{
76
- char *acr;
37
BdrvGraphRWlock *brdv_graph;
77
+ char *key, *acr;
38
@@ -XXX,XX +XXX,XX @@ static uint32_t reader_count(void)
78
int r;
39
assert((int32_t)rd >= 0);
79
GString *accu;
40
return rd;
80
RbdAuthModeList *auth;
41
}
81
42
-#endif
82
- if (secretid) {
43
83
- gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
44
void bdrv_graph_wrlock(BlockDriverState *bs)
84
- errp);
45
{
85
- if (!secret) {
46
AioContext *ctx = NULL;
86
- return -1;
47
87
+ if (opts->key_secret) {
48
GLOBAL_STATE_CODE();
88
+ key = qcrypto_secret_lookup_as_base64(opts->key_secret, errp);
49
- /*
89
+ if (!key) {
50
- * TODO Some callers hold an AioContext lock when this is called, which
90
+ return -EIO;
51
- * causes deadlocks. Reenable once the AioContext locking is cleaned up (or
91
+ }
52
- * AioContext locks are gone).
92
+ r = rados_conf_set(cluster, "key", key);
53
- */
93
+ g_free(key);
54
-#if 0
94
+ if (r < 0) {
55
assert(!qatomic_read(&has_writer));
95
+ error_setg_errno(errp, -r, "Could not set 'key'");
56
-#endif
96
+ return r;
57
97
}
58
/*
98
-
59
* Release only non-mainloop AioContext. The mainloop often relies on the
99
- rados_conf_set(cluster, "key", secret);
60
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(BlockDriverState *bs)
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
}
61
}
134
}
62
}
135
63
136
- if (qemu_rbd_set_auth(*cluster, secretid, opts, errp) < 0) {
64
-#if 0
137
- r = -EIO;
65
/* Make sure that constantly arriving new I/O doesn't cause starvation */
138
+ r = qemu_rbd_set_auth(*cluster, opts, errp);
66
bdrv_drain_all_begin_nopoll();
139
+ if (r < 0) {
67
140
goto failed_shutdown;
68
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(BlockDriverState *bs)
69
} while (reader_count() >= 1);
70
71
bdrv_drain_all_end();
72
-#endif
73
74
if (ctx) {
75
aio_context_acquire(bdrv_get_aio_context(bs));
76
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(BlockDriverState *bs)
77
void bdrv_graph_wrunlock(void)
78
{
79
GLOBAL_STATE_CODE();
80
-#if 0
81
QEMU_LOCK_GUARD(&aio_context_list_lock);
82
assert(qatomic_read(&has_writer));
83
84
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrunlock(void)
85
86
/* Wake up all coroutine that are waiting to read the graph */
87
qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
88
-#endif
89
}
90
91
void coroutine_fn bdrv_graph_co_rdlock(void)
92
{
93
- /* TODO Reenable when wrlock is reenabled */
94
-#if 0
95
BdrvGraphRWlock *bdrv_graph;
96
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
97
98
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_graph_co_rdlock(void)
99
qemu_co_queue_wait(&reader_queue, &aio_context_list_lock);
100
}
141
}
101
}
142
102
-#endif
103
}
104
105
void coroutine_fn bdrv_graph_co_rdunlock(void)
106
{
107
-#if 0
108
BdrvGraphRWlock *bdrv_graph;
109
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
110
111
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_graph_co_rdunlock(void)
112
if (qatomic_read(&has_writer)) {
113
aio_wait_kick();
114
}
115
-#endif
116
}
117
118
void bdrv_graph_rdlock_main_loop(void)
119
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_rdunlock_main_loop(void)
120
void assert_bdrv_graph_readable(void)
121
{
122
/* reader_count() is slow due to aio_context_list_lock lock contention */
123
- /* TODO Reenable when wrlock is reenabled */
124
-#if 0
125
#ifdef CONFIG_DEBUG_GRAPH_LOCK
126
assert(qemu_in_main_thread() || reader_count());
127
#endif
128
-#endif
129
}
130
131
void assert_bdrv_graph_writable(void)
132
{
133
assert(qemu_in_main_thread());
134
- /* TODO Reenable when wrlock is reenabled */
135
-#if 0
136
assert(qatomic_read(&has_writer));
137
-#endif
138
}
143
--
139
--
144
2.13.6
140
2.41.0
145
146
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
-blockdev and blockdev-add silently ignore empty objects and arrays in
3
raw_co_getlength is called by handle_aiocb_write_zeroes, which is not a coroutine
4
their argument. That's because qmp_blockdev_add() converts the
4
function. This is harmless because raw_co_getlength does not actually suspend,
5
argument to a flat QDict, and qdict_flatten() eats empty QDict and
5
but in the interest of clarity make it a non-coroutine_fn that is just wrapped
6
QList members. For instance, we ignore an empty BlockdevOptions
6
by the coroutine_fn raw_co_getlength. Likewise, check_cache_dropped was only
7
member @cache. No real harm, as absent means the same as empty there.
7
a coroutine_fn because it called raw_co_getlength, so it can be made non-coroutine
8
as well.
8
9
9
Thus, the flaw puts an artificial restriction on the QAPI schema: we
10
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
can't have potentially empty objects and arrays within
11
Message-ID: <20230601115145.196465-2-pbonzini@redhat.com>
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>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
14
---
25
qobject/block-qdict.c | 54 +++++++++++++++++++++++++++++------------------
15
block/file-posix.c | 29 +++++++++++++++++------------
26
tests/check-block-qdict.c | 38 ++++++++++++++++++++++++++-------
16
1 file changed, 17 insertions(+), 12 deletions(-)
27
2 files changed, 63 insertions(+), 29 deletions(-)
28
17
29
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
18
diff --git a/block/file-posix.c b/block/file-posix.c
30
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
31
--- a/qobject/block-qdict.c
20
--- a/block/file-posix.c
32
+++ b/qobject/block-qdict.c
21
+++ b/block/file-posix.c
33
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
22
@@ -XXX,XX +XXX,XX @@ static int fd_open(BlockDriverState *bs)
23
return -EIO;
24
}
25
26
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs);
27
+static int64_t raw_getlength(BlockDriverState *bs);
28
29
typedef struct RawPosixAIOData {
30
BlockDriverState *bs;
31
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_write_zeroes(void *opaque)
32
#ifdef CONFIG_FALLOCATE
33
/* Last resort: we are trying to extend the file with zeroed data. This
34
* can be done via fallocate(fd, 0) */
35
- len = raw_co_getlength(aiocb->bs);
36
+ len = raw_getlength(aiocb->bs);
37
if (s->has_fallocate && len >= 0 && aiocb->aio_offset >= len) {
38
int ret = do_fallocate(s->fd, 0, aiocb->aio_offset, aiocb->aio_nbytes);
39
if (ret == 0 || ret != -ENOTSUP) {
40
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
41
}
42
43
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
44
- int64_t cur_length = raw_co_getlength(bs);
45
+ int64_t cur_length = raw_getlength(bs);
46
47
if (offset != cur_length && exact) {
48
error_setg(errp, "Cannot resize device files");
49
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
50
}
51
52
#ifdef __OpenBSD__
53
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
54
+static int64_t raw_getlength(BlockDriverState *bs)
34
{
55
{
35
QObject *value;
56
BDRVRawState *s = bs->opaque;
36
const QListEntry *entry;
57
int fd = s->fd;
37
+ QDict *dict_val;
58
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
38
+ QList *list_val;
59
return st.st_size;
39
char *new_key;
60
}
40
int i;
61
#elif defined(__NetBSD__)
41
62
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
42
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
63
+static int64_t raw_getlength(BlockDriverState *bs)
43
64
{
44
for (i = 0; entry; entry = qlist_next(entry), i++) {
65
BDRVRawState *s = bs->opaque;
45
value = qlist_entry_obj(entry);
66
int fd = s->fd;
46
+ dict_val = qobject_to(QDict, value);
67
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
47
+ list_val = qobject_to(QList, value);
68
return st.st_size;
48
new_key = g_strdup_printf("%s.%i", prefix, i);
69
}
49
70
#elif defined(__sun__)
50
/*
71
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
51
* Flatten non-empty QDict and QList recursively into @target,
72
+static int64_t raw_getlength(BlockDriverState *bs)
52
* copy other objects to @target
73
{
74
BDRVRawState *s = bs->opaque;
75
struct dk_minfo minfo;
76
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
77
return size;
78
}
79
#elif defined(CONFIG_BSD)
80
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
81
+static int64_t raw_getlength(BlockDriverState *bs)
82
{
83
BDRVRawState *s = bs->opaque;
84
int fd = s->fd;
85
@@ -XXX,XX +XXX,XX @@ again:
86
return size;
87
}
88
#else
89
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
90
+static int64_t raw_getlength(BlockDriverState *bs)
91
{
92
BDRVRawState *s = bs->opaque;
93
int ret;
94
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
95
}
96
#endif
97
98
+static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
99
+{
100
+ return raw_getlength(bs);
101
+}
102
+
103
static int64_t coroutine_fn raw_co_get_allocated_file_size(BlockDriverState *bs)
104
{
105
struct stat st;
106
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
107
* round up if necessary.
53
*/
108
*/
54
- if (qobject_type(value) == QTYPE_QDICT) {
109
if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
55
- qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
110
- int64_t file_length = raw_co_getlength(bs);
56
- } else if (qobject_type(value) == QTYPE_QLIST) {
111
+ int64_t file_length = raw_getlength(bs);
57
- qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
112
if (file_length > 0) {
58
+ if (dict_val && qdict_size(dict_val)) {
113
/* Ignore errors, this is just a safeguard */
59
+ qdict_flatten_qdict(dict_val, target, new_key);
114
assert(hole == file_length);
60
+ } else if (list_val && !qlist_empty(list_val)) {
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
61
+ qdict_flatten_qlist(list_val, target, new_key);
116
62
} else {
117
#if defined(__linux__)
63
qdict_put_obj(target, new_key, qobject_ref(value));
118
/* Verify that the file is not in the page cache */
64
}
119
-static void coroutine_fn check_cache_dropped(BlockDriverState *bs, Error **errp)
65
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
120
+static void check_cache_dropped(BlockDriverState *bs, Error **errp)
66
{
121
{
67
QObject *value;
122
const size_t window_size = 128 * 1024 * 1024;
68
const QDictEntry *entry, *next;
123
BDRVRawState *s = bs->opaque;
69
+ QDict *dict_val;
124
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn check_cache_dropped(BlockDriverState *bs, Error **errp)
70
+ QList *list_val;
125
page_size = sysconf(_SC_PAGESIZE);
71
char *new_key;
126
vec = g_malloc(DIV_ROUND_UP(window_size, page_size));
72
127
73
entry = qdict_first(qdict);
128
- end = raw_co_getlength(bs);
74
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
129
+ end = raw_getlength(bs);
75
while (entry != NULL) {
130
76
next = qdict_next(qdict, entry);
131
for (offset = 0; offset < end; offset += window_size) {
77
value = qdict_entry_value(entry);
132
void *new_window;
78
+ dict_val = qobject_to(QDict, value);
133
@@ -XXX,XX +XXX,XX @@ static int cdrom_reopen(BlockDriverState *bs)
79
+ list_val = qobject_to(QList, value);
134
80
new_key = NULL;
135
static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs)
81
136
{
82
if (prefix) {
137
- return raw_co_getlength(bs) > 0;
83
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
138
+ return raw_getlength(bs) > 0;
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
}
139
}
102
140
103
/**
141
static void coroutine_fn cdrom_co_eject(BlockDriverState *bs, bool eject_flag)
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
--
142
--
262
2.13.6
143
2.41.0
263
264
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Parameter "filename" is deprecated since commit 91589d9e5ca, v2.10.0.
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
Time to get rid of it.
4
and they can suspend. Change calls to co_wrappers to use the non-wrapped
5
functions, which in turn requires adding GRAPH_RDLOCK annotations.
5
6
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-ID: <20230601115145.196465-3-pbonzini@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
11
---
10
block/rbd.c | 16 ----------------
12
block/qed-check.c | 5 +++--
11
1 file changed, 16 deletions(-)
13
block/qed.c | 7 ++++---
14
2 files changed, 7 insertions(+), 5 deletions(-)
12
15
13
diff --git a/block/rbd.c b/block/rbd.c
16
diff --git a/block/qed-check.c b/block/qed-check.c
14
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
15
--- a/block/rbd.c
18
--- a/block/qed-check.c
16
+++ b/block/rbd.c
19
+++ b/block/qed-check.c
17
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
20
@@ -XXX,XX +XXX,XX @@ static void qed_check_for_leaks(QEDCheck *check)
18
QObject *crumpled = NULL;
21
/**
19
const QDictEntry *e;
22
* Mark an image clean once it passes check or has been repaired
20
Error *local_err = NULL;
23
*/
21
- const char *filename;
24
-static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
22
char *keypairs, *secretid;
25
+static void coroutine_fn GRAPH_RDLOCK
23
int r;
26
+qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
24
27
{
25
- /* If we are given a filename, parse the filename, with precedence given to
28
/* Skip if there were unfixable corruptions or I/O errors */
26
- * filename encoded options */
29
if (result->corruptions > 0 || result->check_errors > 0) {
27
- filename = qdict_get_try_str(options, "filename");
30
@@ -XXX,XX +XXX,XX @@ static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
28
- if (filename) {
31
}
29
- warn_report("'filename' option specified. "
32
30
- "This is an unsupported option, and may be deprecated "
33
/* Ensure fixes reach storage before clearing check bit */
31
- "in the future");
34
- bdrv_flush(s->bs);
32
- qemu_rbd_parse_filename(filename, options, &local_err);
35
+ bdrv_co_flush(s->bs);
33
- qdict_del(options, "filename");
36
34
- if (local_err) {
37
s->header.features &= ~QED_F_NEED_CHECK;
35
- error_propagate(errp, local_err);
38
qed_write_header_sync(s);
36
- return -EINVAL;
39
diff --git a/block/qed.c b/block/qed.c
37
- }
40
index XXXXXXX..XXXXXXX 100644
38
- }
41
--- a/block/qed.c
39
-
42
+++ b/block/qed.c
40
keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
43
@@ -XXX,XX +XXX,XX @@ static bool qed_is_image_size_valid(uint64_t image_size, uint32_t cluster_size,
41
if (keypairs) {
44
*
42
qdict_del(options, "=keyvalue-pairs");
45
* The string is NUL-terminated.
46
*/
47
-static int qed_read_string(BdrvChild *file, uint64_t offset, size_t n,
48
- char *buf, size_t buflen)
49
+static int coroutine_fn GRAPH_RDLOCK
50
+qed_read_string(BdrvChild *file, uint64_t offset,
51
+ size_t n, char *buf, size_t buflen)
52
{
53
int ret;
54
if (n >= buflen) {
55
return -EINVAL;
56
}
57
- ret = bdrv_pread(file, offset, n, buf, 0);
58
+ ret = bdrv_co_pread(file, offset, n, buf, 0);
59
if (ret < 0) {
60
return ret;
61
}
43
--
62
--
44
2.13.6
63
2.41.0
45
46
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Parameter "filename" is deprecated since commit 5c3ad1a6a8f, v2.10.0.
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
Time to get rid of it.
4
and they can suspend. Change calls to co_wrappers to use the non-wrapped
5
functions, which in turn requires adding GRAPH_RDLOCK annotations.
5
6
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-ID: <20230601115145.196465-4-pbonzini@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
11
---
10
block/iscsi.c | 23 ++---------------------
12
block/vpc.c | 52 ++++++++++++++++++++++++++--------------------------
11
1 file changed, 2 insertions(+), 21 deletions(-)
13
1 file changed, 26 insertions(+), 26 deletions(-)
12
14
13
diff --git a/block/iscsi.c b/block/iscsi.c
15
diff --git a/block/vpc.c b/block/vpc.c
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/block/iscsi.c
17
--- a/block/vpc.c
16
+++ b/block/iscsi.c
18
+++ b/block/vpc.c
17
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
19
@@ -XXX,XX +XXX,XX @@ static int vpc_reopen_prepare(BDRVReopenState *state,
18
.name = "timeout",
20
* operation (the block bitmaps is updated then), 0 otherwise.
19
.type = QEMU_OPT_NUMBER,
21
* If write is true then err must not be NULL.
20
},
22
*/
21
- {
23
-static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
22
- .name = "filename",
24
- bool write, int *err)
23
- .type = QEMU_OPT_STRING,
25
+static int64_t coroutine_fn GRAPH_RDLOCK
24
- },
26
+get_image_offset(BlockDriverState *bs, uint64_t offset, bool write, int *err)
25
{ /* end of list */ }
27
{
26
},
28
BDRVVPCState *s = bs->opaque;
27
};
29
uint64_t bitmap_offset, block_offset;
28
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
30
@@ -XXX,XX +XXX,XX @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
29
char *initiator_name = NULL;
31
30
QemuOpts *opts;
32
s->last_bitmap_offset = bitmap_offset;
31
Error *local_err = NULL;
33
memset(bitmap, 0xff, s->bitmap_size);
32
- const char *transport_name, *portal, *target, *filename;
34
- r = bdrv_pwrite_sync(bs->file, bitmap_offset, s->bitmap_size, bitmap,
33
+ const char *transport_name, *portal, *target;
35
- 0);
34
#if LIBISCSI_API_VERSION >= (20160603)
36
+ r = bdrv_co_pwrite_sync(bs->file, bitmap_offset, s->bitmap_size, bitmap, 0);
35
enum iscsi_transport_type transport;
37
if (r < 0) {
36
#endif
38
*err = r;
37
int i, ret = 0, timeout = 0, lun;
39
return -2;
38
40
@@ -XXX,XX +XXX,XX @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
39
- /* If we are given a filename, parse the filename, with precedence given to
41
*
40
- * filename encoded options */
42
* Returns 0 on success and < 0 on error
41
- filename = qdict_get_try_str(options, "filename");
43
*/
42
- if (filename) {
44
-static int rewrite_footer(BlockDriverState *bs)
43
- warn_report("'filename' option specified. "
45
+static int coroutine_fn GRAPH_RDLOCK rewrite_footer(BlockDriverState *bs)
44
- "This is an unsupported option, and may be deprecated "
46
{
45
- "in the future");
47
int ret;
46
- iscsi_parse_filename(filename, options, &local_err);
48
BDRVVPCState *s = bs->opaque;
47
- if (local_err) {
49
int64_t offset = s->free_data_block_offset;
48
- ret = -EINVAL;
50
49
- error_propagate(errp, local_err);
51
- ret = bdrv_pwrite_sync(bs->file, offset, sizeof(s->footer), &s->footer, 0);
50
- goto exit;
52
+ ret = bdrv_co_pwrite_sync(bs->file, offset, sizeof(s->footer), &s->footer, 0);
51
- }
53
if (ret < 0)
52
- }
54
return ret;
53
-
55
54
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
56
@@ -XXX,XX +XXX,XX @@ static int rewrite_footer(BlockDriverState *bs)
55
qemu_opts_absorb_qdict(opts, options, &local_err);
57
*
56
if (local_err) {
58
* Returns the sectors' offset in the image file on success and < 0 on error
57
@@ -XXX,XX +XXX,XX @@ out:
59
*/
58
}
60
-static int64_t alloc_block(BlockDriverState *bs, int64_t offset)
59
memset(iscsilun, 0, sizeof(IscsiLun));
61
+static int64_t coroutine_fn GRAPH_RDLOCK
62
+alloc_block(BlockDriverState *bs, int64_t offset)
63
{
64
BDRVVPCState *s = bs->opaque;
65
int64_t bat_offset;
66
@@ -XXX,XX +XXX,XX @@ static int64_t alloc_block(BlockDriverState *bs, int64_t offset)
67
68
/* Initialize the block's bitmap */
69
memset(bitmap, 0xff, s->bitmap_size);
70
- ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset,
71
- s->bitmap_size, bitmap, 0);
72
+ ret = bdrv_co_pwrite_sync(bs->file, s->free_data_block_offset,
73
+ s->bitmap_size, bitmap, 0);
74
if (ret < 0) {
75
return ret;
60
}
76
}
61
-exit:
77
@@ -XXX,XX +XXX,XX @@ static int64_t alloc_block(BlockDriverState *bs, int64_t offset)
62
+
78
/* Write BAT entry to disk */
79
bat_offset = s->bat_offset + (4 * index);
80
bat_value = cpu_to_be32(s->pagetable[index]);
81
- ret = bdrv_pwrite_sync(bs->file, bat_offset, 4, &bat_value, 0);
82
+ ret = bdrv_co_pwrite_sync(bs->file, bat_offset, 4, &bat_value, 0);
83
if (ret < 0)
84
goto fail;
85
86
@@ -XXX,XX +XXX,XX @@ fail:
63
return ret;
87
return ret;
64
}
88
}
65
89
90
-static int coroutine_fn vpc_co_block_status(BlockDriverState *bs,
91
- bool want_zero,
92
- int64_t offset, int64_t bytes,
93
- int64_t *pnum, int64_t *map,
94
- BlockDriverState **file)
95
+static int coroutine_fn GRAPH_RDLOCK
96
+vpc_co_block_status(BlockDriverState *bs, bool want_zero,
97
+ int64_t offset, int64_t bytes,
98
+ int64_t *pnum, int64_t *map,
99
+ BlockDriverState **file)
100
{
101
BDRVVPCState *s = bs->opaque;
102
int64_t image_offset;
103
@@ -XXX,XX +XXX,XX @@ static int calculate_geometry(int64_t total_sectors, uint16_t *cyls,
104
return 0;
105
}
106
107
-static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
108
- int64_t total_sectors)
109
+static int coroutine_fn create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
110
+ int64_t total_sectors)
111
{
112
VHDDynDiskHeader dyndisk_header;
113
uint8_t bat_sector[512];
114
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
115
block_size = 0x200000;
116
num_bat_entries = DIV_ROUND_UP(total_sectors, block_size / 512);
117
118
- ret = blk_pwrite(blk, offset, sizeof(*footer), footer, 0);
119
+ ret = blk_co_pwrite(blk, offset, sizeof(*footer), footer, 0);
120
if (ret < 0) {
121
goto fail;
122
}
123
124
offset = 1536 + ((num_bat_entries * 4 + 511) & ~511);
125
- ret = blk_pwrite(blk, offset, sizeof(*footer), footer, 0);
126
+ ret = blk_co_pwrite(blk, offset, sizeof(*footer), footer, 0);
127
if (ret < 0) {
128
goto fail;
129
}
130
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
131
132
memset(bat_sector, 0xFF, 512);
133
for (i = 0; i < DIV_ROUND_UP(num_bat_entries * 4, 512); i++) {
134
- ret = blk_pwrite(blk, offset, 512, bat_sector, 0);
135
+ ret = blk_co_pwrite(blk, offset, 512, bat_sector, 0);
136
if (ret < 0) {
137
goto fail;
138
}
139
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
140
/* Write the header */
141
offset = 512;
142
143
- ret = blk_pwrite(blk, offset, sizeof(dyndisk_header), &dyndisk_header, 0);
144
+ ret = blk_co_pwrite(blk, offset, sizeof(dyndisk_header), &dyndisk_header, 0);
145
if (ret < 0) {
146
goto fail;
147
}
148
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
149
return ret;
150
}
151
152
-static int create_fixed_disk(BlockBackend *blk, VHDFooter *footer,
153
- int64_t total_size, Error **errp)
154
+static int coroutine_fn create_fixed_disk(BlockBackend *blk, VHDFooter *footer,
155
+ int64_t total_size, Error **errp)
156
{
157
int ret;
158
159
/* Add footer to total size */
160
total_size += sizeof(*footer);
161
162
- ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
163
+ ret = blk_co_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
164
if (ret < 0) {
165
return ret;
166
}
167
168
- ret = blk_pwrite(blk, total_size - sizeof(*footer), sizeof(*footer),
169
- footer, 0);
170
+ ret = blk_co_pwrite(blk, total_size - sizeof(*footer), sizeof(*footer),
171
+ footer, 0);
172
if (ret < 0) {
173
error_setg_errno(errp, -ret, "Unable to write VHD header");
174
return ret;
66
--
175
--
67
2.13.6
176
2.41.0
68
69
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
There's no need to restart the loop. We don't elsewhere, e.g. in
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
qdict_extract_subqdict(), qdict_join() and qemu_opts_absorb_qdict().
4
and they can suspend. Change calls to co_wrappers to use the non-wrapped
5
Simplify accordingly.
5
functions, which in turn requires adding GRAPH_RDLOCK annotations.
6
6
7
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-ID: <20230601115145.196465-5-pbonzini@redhat.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
---
11
qobject/block-qdict.c | 18 +++---------------
12
block/bochs.c | 7 ++++---
12
1 file changed, 3 insertions(+), 15 deletions(-)
13
1 file changed, 4 insertions(+), 3 deletions(-)
13
14
14
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
15
diff --git a/block/bochs.c b/block/bochs.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/qobject/block-qdict.c
17
--- a/block/bochs.c
17
+++ b/qobject/block-qdict.c
18
+++ b/block/bochs.c
18
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
19
@@ -XXX,XX +XXX,XX @@ static void bochs_refresh_limits(BlockDriverState *bs, Error **errp)
19
QObject *value;
20
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
20
const QDictEntry *entry, *next;
21
}
21
char *new_key;
22
22
- bool delete;
23
-static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
23
24
+static int64_t coroutine_fn GRAPH_RDLOCK
24
entry = qdict_first(qdict);
25
+seek_to_sector(BlockDriverState *bs, int64_t sector_num)
25
26
{
26
while (entry != NULL) {
27
BDRVBochsState *s = bs->opaque;
27
-
28
uint64_t offset = sector_num * 512;
28
next = qdict_next(qdict, entry);
29
@@ -XXX,XX +XXX,XX @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
29
value = qdict_entry_value(entry);
30
(s->extent_blocks + s->bitmap_blocks));
30
new_key = NULL;
31
31
- delete = false;
32
/* read in bitmap for current extent */
32
33
- ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8), 1,
33
if (prefix) {
34
- &bitmap_entry, 0);
34
new_key = g_strdup_printf("%s.%s", prefix, entry->key);
35
+ ret = bdrv_co_pread(bs->file, bitmap_offset + (extent_offset / 8), 1,
35
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
36
+ &bitmap_entry, 0);
36
* itself disappears. */
37
if (ret < 0) {
37
qdict_flatten_qdict(qobject_to(QDict, value), target,
38
return ret;
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
}
39
}
65
}
66
--
40
--
67
2.13.6
41
2.41.0
68
69
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Remaining uses of qobject_input_visitor_new_keyval() in the block
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
subsystem:
4
and they can suspend. Because this function operates on a BlockBackend, mark it
5
GRAPH_UNLOCKED.
5
6
6
* block_crypto_open_opts_init()
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Currently doesn't visit any non-string scalars, thus safe. It's
8
Message-ID: <20230601115145.196465-6-pbonzini@redhat.com>
8
called from
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
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>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
11
---
30
block/crypto.c | 12 +++++++++---
12
block.c | 11 ++++++-----
31
block/vdi.c | 8 ++++++--
13
1 file changed, 6 insertions(+), 5 deletions(-)
32
2 files changed, 15 insertions(+), 5 deletions(-)
33
14
34
diff --git a/block/crypto.c b/block/crypto.c
15
diff --git a/block.c b/block.c
35
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
36
--- a/block/crypto.c
17
--- a/block.c
37
+++ b/block/crypto.c
18
+++ b/block.c
38
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
39
#include "qemu/osdep.h"
20
* On success, return @blk's actual length.
40
21
* Otherwise, return -errno.
41
#include "block/block_int.h"
22
*/
42
+#include "block/qdict.h"
23
-static int64_t create_file_fallback_truncate(BlockBackend *blk,
43
#include "sysemu/block-backend.h"
24
- int64_t minimum_size, Error **errp)
44
#include "crypto/block.h"
25
+static int64_t coroutine_fn GRAPH_UNLOCKED
45
#include "qapi/opts-visitor.h"
26
+create_file_fallback_truncate(BlockBackend *blk, int64_t minimum_size,
46
#include "qapi/qapi-visit-crypto.h"
27
+ Error **errp)
47
-#include "qapi/qmp/qdict.h"
28
{
48
#include "qapi/qobject-input-visitor.h"
29
Error *local_err = NULL;
49
#include "qapi/error.h"
30
int64_t size;
50
#include "qemu/option.h"
31
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
51
@@ -XXX,XX +XXX,XX @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
32
52
ret = g_new0(QCryptoBlockOpenOptions, 1);
33
GLOBAL_STATE_CODE();
53
ret->format = format;
34
54
35
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
55
- v = qobject_input_visitor_new_keyval(QOBJECT(opts));
36
- &local_err);
56
+ v = qobject_input_visitor_new_flat_confused(opts, &local_err);
37
+ ret = blk_co_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
57
+ if (local_err) {
38
+ &local_err);
58
+ goto out;
39
if (ret < 0 && ret != -ENOTSUP) {
59
+ }
40
error_propagate(errp, local_err);
60
41
return ret;
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
}
42
}
93
43
94
/* Get the QAPI object */
44
- size = blk_getlength(blk);
95
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
45
+ size = blk_co_getlength(blk);
96
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
46
if (size < 0) {
97
+ if (!v) {
47
error_free(local_err);
98
+ ret = -EINVAL;
48
error_setg_errno(errp, -size,
99
+ goto done;
100
+ }
101
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
102
visit_free(v);
103
104
--
49
--
105
2.13.6
50
2.41.0
106
107
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
and they can suspend. Change calls to co_wrappers to use the non-wrapped
5
functions, which in turn requires adding GRAPH_RDLOCK annotations.
6
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-ID: <20230601115145.196465-7-pbonzini@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
11
---
7
tests/check-block-qdict.c | 57 ++++++++++++++++++++++++-----------------------
12
block/cloop.c | 9 +++++----
8
1 file changed, 29 insertions(+), 28 deletions(-)
13
1 file changed, 5 insertions(+), 4 deletions(-)
9
14
10
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
15
diff --git a/block/cloop.c b/block/cloop.c
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/check-block-qdict.c
17
--- a/block/cloop.c
13
+++ b/tests/check-block-qdict.c
18
+++ b/block/cloop.c
14
@@ -XXX,XX +XXX,XX @@ static void qdict_defaults_test(void)
19
@@ -XXX,XX +XXX,XX @@ static void cloop_refresh_limits(BlockDriverState *bs, Error **errp)
15
20
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
16
static void qdict_flatten_test(void)
21
}
22
23
-static inline int cloop_read_block(BlockDriverState *bs, int block_num)
24
+static int coroutine_fn GRAPH_RDLOCK
25
+cloop_read_block(BlockDriverState *bs, int block_num)
17
{
26
{
18
- QList *list1 = qlist_new();
27
BDRVCloopState *s = bs->opaque;
19
- QList *list2 = qlist_new();
28
20
- QDict *dict1 = qdict_new();
29
@@ -XXX,XX +XXX,XX @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
21
- QDict *dict2 = qdict_new();
30
int ret;
22
- QDict *dict3 = qdict_new();
31
uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
23
+ QList *e_1 = qlist_new();
32
24
+ QList *e = qlist_new();
33
- ret = bdrv_pread(bs->file, s->offsets[block_num], bytes,
25
+ QDict *e_1_2 = qdict_new();
34
- s->compressed_block, 0);
26
+ QDict *f = qdict_new();
35
+ ret = bdrv_co_pread(bs->file, s->offsets[block_num], bytes,
27
+ QDict *root = qdict_new();
36
+ s->compressed_block, 0);
28
37
if (ret < 0) {
29
/*
38
return -1;
30
* Test the flattening of
39
}
31
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
40
@@ -XXX,XX +XXX,XX @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
32
* }
41
return 0;
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
}
42
}
89
43
90
static void qdict_array_split_test(void)
44
-static int coroutine_fn
45
+static int coroutine_fn GRAPH_RDLOCK
46
cloop_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
47
QEMUIOVector *qiov, BdrvRequestFlags flags)
48
{
91
--
49
--
92
2.13.6
50
2.41.0
93
94
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Pure code motion, except for two brace placements and a comment
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
tweaked to appease checkpatch.
4
and they can suspend. Change calls to co_wrappers to use the non-wrapped
5
functions, which in turn requires adding GRAPH_RDLOCK annotations.
5
6
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-ID: <20230601115145.196465-8-pbonzini@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
11
---
10
qobject/block-qdict.c | 640 ++++++++++++++++++++++++++++++++++++++++++++
12
block/dmg.c | 21 +++++++++++----------
11
qobject/qdict.c | 629 --------------------------------------------
13
1 file changed, 11 insertions(+), 10 deletions(-)
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
14
21
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
15
diff --git a/block/dmg.c b/block/dmg.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
16
index XXXXXXX..XXXXXXX 100644
669
--- a/qobject/qdict.c
17
--- a/block/dmg.c
670
+++ b/qobject/qdict.c
18
+++ b/block/dmg.c
671
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ err:
672
*/
20
return s->n_chunks; /* error */
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
}
21
}
693
-
22
694
-/**
23
-static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
695
- * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
24
+static int coroutine_fn GRAPH_RDLOCK
696
- * value of 'key' in 'src' is copied there (and the refcount increased
25
+dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
697
- * accordingly).
26
{
698
- */
27
BDRVDMGState *s = bs->opaque;
699
-void qdict_copy_default(QDict *dst, QDict *src, const char *key)
28
700
-{
29
@@ -XXX,XX +XXX,XX @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
701
- QObject *val;
30
case UDZO: { /* zlib compressed */
702
-
31
/* we need to buffer, because only the chunk as whole can be
703
- if (qdict_haskey(dst, key)) {
32
* inflated. */
704
- return;
33
- ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
705
- }
34
- s->compressed_chunk, 0);
706
-
35
+ ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
707
- val = qdict_get(src, key);
36
+ s->compressed_chunk, 0);
708
- if (val) {
37
if (ret < 0) {
709
- qdict_put_obj(dst, key, qobject_ref(val));
38
return -1;
710
- }
39
}
711
-}
40
@@ -XXX,XX +XXX,XX @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
712
-
41
}
713
-/**
42
/* we need to buffer, because only the chunk as whole can be
714
- * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
43
* inflated. */
715
- * new QString initialised by 'val' is put there.
44
- ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
716
- */
45
- s->compressed_chunk, 0);
717
-void qdict_set_default_str(QDict *dst, const char *key, const char *val)
46
+ ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
718
-{
47
+ s->compressed_chunk, 0);
719
- if (qdict_haskey(dst, key)) {
48
if (ret < 0) {
720
- return;
49
return -1;
721
- }
50
}
722
-
51
@@ -XXX,XX +XXX,XX @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
723
- qdict_put_str(dst, key, val);
52
}
724
-}
53
/* we need to buffer, because only the chunk as whole can be
725
-
54
* inflated. */
726
-static void qdict_flatten_qdict(QDict *qdict, QDict *target,
55
- ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
727
- const char *prefix);
56
- s->compressed_chunk, 0);
728
-
57
+ ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
729
-static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
58
+ s->compressed_chunk, 0);
730
-{
59
if (ret < 0) {
731
- QObject *value;
60
return -1;
732
- const QListEntry *entry;
61
}
733
- char *new_key;
62
@@ -XXX,XX +XXX,XX @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
734
- int i;
63
}
735
-
64
break;
736
- /* This function is never called with prefix == NULL, i.e., it is always
65
case UDRW: /* copy */
737
- * called from within qdict_flatten_q(list|dict)(). Therefore, it does not
66
- ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
738
- * need to remove list entries during the iteration (the whole list will be
67
- s->uncompressed_chunk, 0);
739
- * deleted eventually anyway from qdict_flatten_qdict()). */
68
+ ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
740
- assert(prefix);
69
+ s->uncompressed_chunk, 0);
741
-
70
if (ret < 0) {
742
- entry = qlist_first(qlist);
71
return -1;
743
-
72
}
744
- for (i = 0; entry; entry = qlist_next(entry), i++) {
73
@@ -XXX,XX +XXX,XX @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
745
- value = qlist_entry_obj(entry);
74
return 0;
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
}
75
}
1998
76
1999
-static void qdict_defaults_test(void)
77
-static int coroutine_fn
2000
-{
78
+static int coroutine_fn GRAPH_RDLOCK
2001
- QDict *dict, *copy;
79
dmg_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
2002
-
80
QEMUIOVector *qiov, BdrvRequestFlags flags)
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
{
81
{
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
--
82
--
2712
2.13.6
83
2.41.0
2713
2714
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The previous commit fixed -blockdev breakage due to misuse of the
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
qobject input visitor's keyval flavor in bdrv_file_open(). The commit
4
and they can suspend. Change calls to co_wrappers to use the non-wrapped
5
message explain why using the plain flavor would be just as wrong; it
5
functions, which in turn requires adding GRAPH_RDLOCK annotations.
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
6
10
$ qemu-system-x86 -drive node-name=n1,driver=nbd,server.type=inet,server.host=localhost,server.port=1234,server.numeric=off
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
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
8
Message-ID: <20230601115145.196465-9-pbonzini@redhat.com>
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>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
11
---
21
block/nbd.c | 12 ++----------
12
block/vmdk.c | 27 ++++++++++++++-------------
22
block/sheepdog.c | 12 ++----------
13
1 file changed, 14 insertions(+), 13 deletions(-)
23
block/ssh.c | 12 ++----------
24
3 files changed, 6 insertions(+), 30 deletions(-)
25
14
26
diff --git a/block/nbd.c b/block/nbd.c
15
diff --git a/block/vmdk.c b/block/vmdk.c
27
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
28
--- a/block/nbd.c
17
--- a/block/vmdk.c
29
+++ b/block/nbd.c
18
+++ b/block/vmdk.c
30
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
19
@@ -XXX,XX +XXX,XX @@ out:
31
goto done;
20
return ret;
21
}
22
23
-static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
24
+static int coroutine_fn GRAPH_RDLOCK
25
+vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
26
{
27
char *desc, *tmp_desc;
28
char *p_name, *tmp_str;
29
@@ -XXX,XX +XXX,XX @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
30
31
desc = g_malloc0(DESC_SIZE);
32
tmp_desc = g_malloc0(DESC_SIZE);
33
- ret = bdrv_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
34
+ ret = bdrv_co_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
35
if (ret < 0) {
36
goto out;
32
}
37
}
33
38
@@ -XXX,XX +XXX,XX @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
34
- crumpled_addr = qdict_crumple(addr, errp);
39
pstrcat(desc, DESC_SIZE, tmp_desc);
35
+ crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp);
36
if (!crumpled_addr) {
37
goto done;
38
}
40
}
39
41
40
- /*
42
- ret = bdrv_pwrite_sync(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
41
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
43
+ ret = bdrv_co_pwrite_sync(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
42
- * server.type=inet. .to doesn't matter, it's ignored anyway.
44
43
- * That's because when @options come from -blockdev or
45
out:
44
- * blockdev_add, members are typed according to the QAPI schema,
46
g_free(desc);
45
- * but when they come from -drive, they're all QString. The
47
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
46
- * visitor expects the former.
48
return ret;
47
- */
49
}
48
- iv = qobject_input_visitor_new(crumpled_addr);
50
49
+ iv = qobject_input_visitor_new_keyval(crumpled_addr);
51
-static int GRAPH_UNLOCKED
50
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
52
+static int coroutine_fn GRAPH_UNLOCKED
51
if (local_err) {
53
vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
52
error_propagate(errp, local_err);
54
bool zeroed_grain, Error **errp)
53
diff --git a/block/sheepdog.c b/block/sheepdog.c
55
{
54
index XXXXXXX..XXXXXXX 100644
56
@@ -XXX,XX +XXX,XX @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
55
--- a/block/sheepdog.c
57
int gd_buf_size;
56
+++ b/block/sheepdog.c
58
57
@@ -XXX,XX +XXX,XX @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
59
if (flat) {
58
60
- ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
59
qdict_extract_subqdict(options, &server, "server.");
61
+ ret = blk_co_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
60
62
goto exit;
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
}
63
}
66
64
magic = cpu_to_be32(VMDK4_MAGIC);
67
- /*
65
@@ -XXX,XX +XXX,XX @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
68
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
66
header.check_bytes[3] = 0xa;
69
- * server.type=inet. .to doesn't matter, it's ignored anyway.
67
70
- * That's because when @options come from -blockdev or
68
/* write all the data */
71
- * blockdev_add, members are typed according to the QAPI schema,
69
- ret = blk_pwrite(blk, 0, sizeof(magic), &magic, 0);
72
- * but when they come from -drive, they're all QString. The
70
+ ret = blk_co_pwrite(blk, 0, sizeof(magic), &magic, 0);
73
- * visitor expects the former.
71
if (ret < 0) {
74
- */
72
error_setg(errp, QERR_IO_ERROR);
75
- iv = qobject_input_visitor_new(crumpled_server);
73
goto exit;
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
}
74
}
86
75
- ret = blk_pwrite(blk, sizeof(magic), sizeof(header), &header, 0);
87
/* Create the QAPI object */
76
+ ret = blk_co_pwrite(blk, sizeof(magic), sizeof(header), &header, 0);
88
- crumpled = qdict_crumple(options, errp);
77
if (ret < 0) {
89
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
78
error_setg(errp, QERR_IO_ERROR);
90
if (crumpled == NULL) {
79
goto exit;
91
goto fail;
92
}
80
}
93
81
94
- /*
82
- ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
95
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive.
83
- PREALLOC_MODE_OFF, 0, errp);
96
- * .to doesn't matter, it's ignored anyway.
84
+ ret = blk_co_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
97
- * That's because when @options come from -blockdev or
85
+ PREALLOC_MODE_OFF, 0, errp);
98
- * blockdev_add, members are typed according to the QAPI schema,
86
if (ret < 0) {
99
- * but when they come from -drive, they're all QString. The
87
goto exit;
100
- * visitor expects the former.
88
}
101
- */
89
@@ -XXX,XX +XXX,XX @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
102
- v = qobject_input_visitor_new(crumpled);
90
i < gt_count; i++, tmp += gt_size) {
103
+ v = qobject_input_visitor_new_keyval(crumpled);
91
gd_buf[i] = cpu_to_le32(tmp);
104
visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err);
92
}
105
visit_free(v);
93
- ret = blk_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE,
106
qobject_unref(crumpled);
94
- gd_buf_size, gd_buf, 0);
95
+ ret = blk_co_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE,
96
+ gd_buf_size, gd_buf, 0);
97
if (ret < 0) {
98
error_setg(errp, QERR_IO_ERROR);
99
goto exit;
100
@@ -XXX,XX +XXX,XX @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
101
i < gt_count; i++, tmp += gt_size) {
102
gd_buf[i] = cpu_to_le32(tmp);
103
}
104
- ret = blk_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE,
105
- gd_buf_size, gd_buf, 0);
106
+ ret = blk_co_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE,
107
+ gd_buf_size, gd_buf, 0);
108
if (ret < 0) {
109
error_setg(errp, QERR_IO_ERROR);
110
}
107
--
111
--
108
2.13.6
112
2.41.0
109
110
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Configuration flows through the block subsystem in a rather peculiar
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
way. Configuration made with -drive enters it as QemuOpts.
4
and they can suspend. Change calls to co_wrappers to use the non-wrapped
5
Configuration made with -blockdev / blockdev-add enters it as QAPI
5
functions, which in turn requires adding GRAPH_RDLOCK annotations.
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
6
12
$ qemu-system-x86_64 -blockdev node-name=n1,driver=nfs,server.type=inet,server.host=localhost,path=/foo/bar,user=1234
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
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
8
Message-ID: <20230601115145.196465-10-pbonzini@redhat.com>
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>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
66
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
67
---
11
---
68
include/block/qdict.h | 1 +
12
block/vhdx.h | 5 ++--
69
block/nfs.c | 2 +-
13
block/vhdx-log.c | 36 +++++++++++++-----------
70
block/parallels.c | 2 +-
14
block/vhdx.c | 73 +++++++++++++++++++++++-------------------------
71
block/qcow.c | 2 +-
15
3 files changed, 57 insertions(+), 57 deletions(-)
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
16
81
diff --git a/include/block/qdict.h b/include/block/qdict.h
17
diff --git a/block/vhdx.h b/block/vhdx.h
82
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
83
--- a/include/block/qdict.h
19
--- a/block/vhdx.h
84
+++ b/include/block/qdict.h
20
+++ b/block/vhdx.h
85
@@ -XXX,XX +XXX,XX @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
21
@@ -XXX,XX +XXX,XX @@ bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset);
86
void qdict_array_split(QDict *src, QList **dst);
22
int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
87
int qdict_array_entries(QDict *src, const char *subqdict);
23
Error **errp);
88
QObject *qdict_crumple(const QDict *src, Error **errp);
24
89
+QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp);
25
-int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
90
void qdict_flatten(QDict *qdict);
26
- void *data, uint32_t length, uint64_t offset);
91
27
+int coroutine_fn GRAPH_RDLOCK
92
typedef struct QDictRenames {
28
+vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
93
diff --git a/block/nfs.c b/block/nfs.c
29
+ void *data, uint32_t length, uint64_t offset);
30
31
static inline void leguid_to_cpus(MSGUID *guid)
32
{
33
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
94
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
95
--- a/block/nfs.c
35
--- a/block/vhdx-log.c
96
+++ b/block/nfs.c
36
+++ b/block/vhdx-log.c
97
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
37
@@ -XXX,XX +XXX,XX @@ exit:
98
const QDictEntry *e;
38
* It is assumed that 'buffer' is at least 4096*num_sectors large.
99
Error *local_err = NULL;
39
*
100
40
* 0 is returned on success, -errno otherwise */
101
- crumpled = qdict_crumple(options, errp);
41
-static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
102
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
42
- uint32_t *sectors_written, void *buffer,
103
if (crumpled == NULL) {
43
- uint32_t num_sectors)
104
return NULL;
44
+static int coroutine_fn GRAPH_RDLOCK
105
}
45
+vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
106
diff --git a/block/parallels.c b/block/parallels.c
46
+ uint32_t *sectors_written, void *buffer,
107
index XXXXXXX..XXXXXXX 100644
47
+ uint32_t num_sectors)
108
--- a/block/parallels.c
48
{
109
+++ b/block/parallels.c
49
int ret = 0;
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
50
uint64_t offset;
111
qdict_put_str(qdict, "driver", "parallels");
51
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
112
qdict_put_str(qdict, "file", bs->node_name);
52
/* full */
113
53
break;
114
- qobj = qdict_crumple(qdict, errp);
54
}
115
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
55
- ret = bdrv_pwrite(bs->file, offset, VHDX_LOG_SECTOR_SIZE, buffer_tmp,
116
qobject_unref(qdict);
56
- 0);
117
qdict = qobject_to(QDict, qobj);
57
+ ret = bdrv_co_pwrite(bs->file, offset, VHDX_LOG_SECTOR_SIZE, buffer_tmp, 0);
118
if (qdict == NULL) {
58
if (ret < 0) {
119
diff --git a/block/qcow.c b/block/qcow.c
59
goto exit;
120
index XXXXXXX..XXXXXXX 100644
60
}
121
--- a/block/qcow.c
61
@@ -XXX,XX +XXX,XX @@ static void vhdx_log_raw_to_le_sector(VHDXLogDescriptor *desc,
122
+++ b/block/qcow.c
62
}
123
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
63
124
qdict_put_str(qdict, "driver", "qcow");
64
125
qdict_put_str(qdict, "file", bs->node_name);
65
-static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
126
66
- void *data, uint32_t length, uint64_t offset)
127
- qobj = qdict_crumple(qdict, errp);
67
+static int coroutine_fn GRAPH_RDLOCK
128
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
68
+vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
129
qobject_unref(qdict);
69
+ void *data, uint32_t length, uint64_t offset)
130
qdict = qobject_to(QDict, qobj);
70
{
131
if (qdict == NULL) {
71
int ret = 0;
132
diff --git a/block/qcow2.c b/block/qcow2.c
72
void *buffer = NULL;
133
index XXXXXXX..XXXXXXX 100644
73
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
134
--- a/block/qcow2.c
74
135
+++ b/block/qcow2.c
75
sectors += partial_sectors;
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
76
137
qdict_put_str(qdict, "file", bs->node_name);
77
- file_length = bdrv_getlength(bs->file->bs);
138
78
+ file_length = bdrv_co_getlength(bs->file->bs);
139
/* Now get the QAPI type BlockdevCreateOptions */
79
if (file_length < 0) {
140
- qobj = qdict_crumple(qdict, errp);
80
ret = file_length;
141
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
81
goto exit;
142
qobject_unref(qdict);
82
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
143
qdict = qobject_to(QDict, qobj);
83
144
if (qdict == NULL) {
84
if (i == 0 && leading_length) {
145
diff --git a/block/qed.c b/block/qed.c
85
/* partial sector at the front of the buffer */
146
index XXXXXXX..XXXXXXX 100644
86
- ret = bdrv_pread(bs->file, file_offset, VHDX_LOG_SECTOR_SIZE,
147
--- a/block/qed.c
87
- merged_sector, 0);
148
+++ b/block/qed.c
88
+ ret = bdrv_co_pread(bs->file, file_offset, VHDX_LOG_SECTOR_SIZE,
149
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
89
+ merged_sector, 0);
150
qdict_put_str(qdict, "driver", "qed");
90
if (ret < 0) {
151
qdict_put_str(qdict, "file", bs->node_name);
91
goto exit;
152
92
}
153
- qobj = qdict_crumple(qdict, errp);
93
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
154
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
94
sector_write = merged_sector;
155
qobject_unref(qdict);
95
} else if (i == sectors - 1 && trailing_length) {
156
qdict = qobject_to(QDict, qobj);
96
/* partial sector at the end of the buffer */
157
if (qdict == NULL) {
97
- ret = bdrv_pread(bs->file, file_offset + trailing_length,
158
diff --git a/block/rbd.c b/block/rbd.c
98
- VHDX_LOG_SECTOR_SIZE - trailing_length,
159
index XXXXXXX..XXXXXXX 100644
99
- merged_sector + trailing_length, 0);
160
--- a/block/rbd.c
100
+ ret = bdrv_co_pread(bs->file, file_offset + trailing_length,
161
+++ b/block/rbd.c
101
+ VHDX_LOG_SECTOR_SIZE - trailing_length,
162
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
102
+ merged_sector + trailing_length, 0);
163
}
103
if (ret < 0) {
164
104
goto exit;
165
/* Convert the remaining options into a QAPI object */
105
}
166
- crumpled = qdict_crumple(options, errp);
106
@@ -XXX,XX +XXX,XX @@ exit:
167
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
107
}
168
if (crumpled == NULL) {
108
169
r = -EINVAL;
109
/* Perform a log write, and then immediately flush the entire log */
170
goto out;
110
-int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
171
diff --git a/block/sheepdog.c b/block/sheepdog.c
111
- void *data, uint32_t length, uint64_t offset)
172
index XXXXXXX..XXXXXXX 100644
112
+int coroutine_fn
173
--- a/block/sheepdog.c
113
+vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
174
+++ b/block/sheepdog.c
114
+ void *data, uint32_t length, uint64_t offset)
175
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
115
{
176
}
116
int ret = 0;
177
117
VHDXLogSequence logs = { .valid = true,
178
/* Get the QAPI object */
118
@@ -XXX,XX +XXX,XX @@ int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
179
- crumpled = qdict_crumple(qdict, errp);
119
180
+ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
120
/* Make sure data written (new and/or changed blocks) is stable
181
if (crumpled == NULL) {
121
* on disk, before creating log entry */
182
ret = -EINVAL;
122
- ret = bdrv_flush(bs);
183
goto fail;
123
+ ret = bdrv_co_flush(bs);
124
if (ret < 0) {
125
goto exit;
126
}
127
@@ -XXX,XX +XXX,XX @@ int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
128
logs.log = s->log;
129
130
/* Make sure log is stable on disk */
131
- ret = bdrv_flush(bs);
132
+ ret = bdrv_co_flush(bs);
133
if (ret < 0) {
134
goto exit;
135
}
184
diff --git a/block/vhdx.c b/block/vhdx.c
136
diff --git a/block/vhdx.c b/block/vhdx.c
185
index XXXXXXX..XXXXXXX 100644
137
index XXXXXXX..XXXXXXX 100644
186
--- a/block/vhdx.c
138
--- a/block/vhdx.c
187
+++ b/block/vhdx.c
139
+++ b/block/vhdx.c
188
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
140
@@ -XXX,XX +XXX,XX @@ exit:
189
qdict_put_str(qdict, "driver", "vhdx");
141
*
190
qdict_put_str(qdict, "file", bs->node_name);
142
* Returns the file offset start of the new payload block
191
143
*/
192
- qobj = qdict_crumple(qdict, errp);
144
-static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
193
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
145
- uint64_t *new_offset, bool *need_zero)
194
qobject_unref(qdict);
146
+static int coroutine_fn GRAPH_RDLOCK
195
qdict = qobject_to(QDict, qobj);
147
+vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
196
if (qdict == NULL) {
148
+ uint64_t *new_offset, bool *need_zero)
197
diff --git a/block/vpc.c b/block/vpc.c
149
{
198
index XXXXXXX..XXXXXXX 100644
150
int64_t current_len;
199
--- a/block/vpc.c
151
200
+++ b/block/vpc.c
152
- current_len = bdrv_getlength(bs->file->bs);
201
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
153
+ current_len = bdrv_co_getlength(bs->file->bs);
202
qdict_put_str(qdict, "driver", "vpc");
154
if (current_len < 0) {
203
qdict_put_str(qdict, "file", bs->node_name);
155
return current_len;
204
156
}
205
- qobj = qdict_crumple(qdict, errp);
157
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
206
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
158
if (*need_zero) {
207
qobject_unref(qdict);
159
int ret;
208
qdict = qobject_to(QDict, qobj);
160
209
if (qdict == NULL) {
161
- ret = bdrv_truncate(bs->file, *new_offset + s->block_size, false,
210
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
162
- PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, NULL);
211
index XXXXXXX..XXXXXXX 100644
163
+ ret = bdrv_co_truncate(bs->file, *new_offset + s->block_size, false,
212
--- a/qobject/block-qdict.c
164
+ PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, NULL);
213
+++ b/qobject/block-qdict.c
165
if (ret != -ENOTSUP) {
214
@@ -XXX,XX +XXX,XX @@
166
*need_zero = false;
215
167
return ret;
216
#include "qemu/osdep.h"
168
}
217
#include "block/qdict.h"
169
}
218
+#include "qapi/qmp/qbool.h"
170
219
#include "qapi/qmp/qlist.h"
171
- return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
220
+#include "qapi/qmp/qnum.h"
172
- PREALLOC_MODE_OFF, 0, NULL);
221
+#include "qapi/qmp/qstring.h"
173
+ return bdrv_co_truncate(bs->file, *new_offset + s->block_size, false,
222
#include "qemu/cutils.h"
174
+ PREALLOC_MODE_OFF, 0, NULL);
223
#include "qapi/error.h"
224
225
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
226
}
175
}
227
176
228
/**
177
/*
229
+ * qdict_crumple_for_keyval_qiv:
178
@@ -XXX,XX +XXX,XX @@ exit:
230
+ * @src: the flat dictionary (only scalar values) to crumple
179
* The first 64KB of the Metadata section is reserved for the metadata
231
+ * @errp: location to store error
180
* header and entries; beyond that, the metadata items themselves reside.
232
+ *
181
*/
233
+ * Like qdict_crumple(), but additionally transforms scalar values so
182
-static int vhdx_create_new_metadata(BlockBackend *blk,
234
+ * the result can be passed to qobject_input_visitor_new_keyval().
183
- uint64_t image_size,
235
+ *
184
- uint32_t block_size,
236
+ * The block subsystem uses this function to prepare its flat QDict
185
- uint32_t sector_size,
237
+ * with possibly confused scalar types for a visit. It should not be
186
- uint64_t metadata_offset,
238
+ * used for anything else, and it should go away once the block
187
- VHDXImageType type)
239
+ * subsystem has been cleaned up.
188
+static int coroutine_fn
240
+ */
189
+vhdx_create_new_metadata(BlockBackend *blk, uint64_t image_size,
241
+QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp)
190
+ uint32_t block_size, uint32_t sector_size,
242
+{
191
+ uint64_t metadata_offset, VHDXImageType type)
243
+ QDict *tmp = NULL;
192
{
244
+ char *buf;
193
int ret = 0;
245
+ const char *s;
194
uint32_t offset = 0;
246
+ const QDictEntry *ent;
195
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_new_metadata(BlockBackend *blk,
247
+ QObject *dst;
196
VHDX_META_FLAGS_IS_VIRTUAL_DISK;
248
+
197
vhdx_metadata_entry_le_export(&md_table_entry[4]);
249
+ for (ent = qdict_first(src); ent; ent = qdict_next(src, ent)) {
198
250
+ buf = NULL;
199
- ret = blk_pwrite(blk, metadata_offset, VHDX_HEADER_BLOCK_SIZE, buffer, 0);
251
+ switch (qobject_type(ent->value)) {
200
+ ret = blk_co_pwrite(blk, metadata_offset, VHDX_HEADER_BLOCK_SIZE, buffer, 0);
252
+ case QTYPE_QNULL:
201
if (ret < 0) {
253
+ case QTYPE_QSTRING:
202
goto exit;
254
+ continue;
203
}
255
+ case QTYPE_QNUM:
204
256
+ s = buf = qnum_to_string(qobject_to(QNum, ent->value));
205
- ret = blk_pwrite(blk, metadata_offset + (64 * KiB),
257
+ break;
206
- VHDX_METADATA_ENTRY_BUFFER_SIZE, entry_buffer, 0);
258
+ case QTYPE_QDICT:
207
+ ret = blk_co_pwrite(blk, metadata_offset + (64 * KiB),
259
+ case QTYPE_QLIST:
208
+ VHDX_METADATA_ENTRY_BUFFER_SIZE, entry_buffer, 0);
260
+ /* @src isn't flat; qdict_crumple() will fail */
209
if (ret < 0) {
261
+ continue;
210
goto exit;
262
+ case QTYPE_QBOOL:
211
}
263
+ s = qbool_get_bool(qobject_to(QBool, ent->value))
212
@@ -XXX,XX +XXX,XX @@ exit:
264
+ ? "on" : "off";
213
* Fixed images: default state of the BAT is fully populated, with
265
+ break;
214
* file offsets and state PAYLOAD_BLOCK_FULLY_PRESENT.
266
+ default:
215
*/
267
+ abort();
216
-static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
268
+ }
217
- uint64_t image_size, VHDXImageType type,
269
+
218
- bool use_zero_blocks, uint64_t file_offset,
270
+ if (!tmp) {
219
- uint32_t length, Error **errp)
271
+ tmp = qdict_clone_shallow(src);
220
+static int coroutine_fn
272
+ }
221
+vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
273
+ qdict_put(tmp, ent->key, qstring_from_str(s));
222
+ uint64_t image_size, VHDXImageType type,
274
+ g_free(buf);
223
+ bool use_zero_blocks, uint64_t file_offset,
275
+ }
224
+ uint32_t length, Error **errp)
276
+
225
{
277
+ dst = qdict_crumple(tmp ?: src, errp);
226
int ret = 0;
278
+ qobject_unref(tmp);
227
uint64_t data_file_offset;
279
+ return dst;
228
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
280
+}
229
if (type == VHDX_TYPE_DYNAMIC) {
281
+
230
/* All zeroes, so we can just extend the file - the end of the BAT
282
+/**
231
* is the furthest thing we have written yet */
283
* qdict_array_entries(): Returns the number of direct array entries if the
232
- ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
284
* sub-QDict of src specified by the prefix in subqdict (or src itself for
233
- 0, errp);
285
* prefix == "") is valid as an array, i.e. the length of the created list if
234
+ ret = blk_co_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
235
+ 0, errp);
236
if (ret < 0) {
237
goto exit;
238
}
239
} else if (type == VHDX_TYPE_FIXED) {
240
- ret = blk_truncate(blk, data_file_offset + image_size, false,
241
- PREALLOC_MODE_OFF, 0, errp);
242
+ ret = blk_co_truncate(blk, data_file_offset + image_size, false,
243
+ PREALLOC_MODE_OFF, 0, errp);
244
if (ret < 0) {
245
goto exit;
246
}
247
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
248
s->bat[sinfo.bat_idx] = cpu_to_le64(s->bat[sinfo.bat_idx]);
249
sector_num += s->sectors_per_block;
250
}
251
- ret = blk_pwrite(blk, file_offset, length, s->bat, 0);
252
+ ret = blk_co_pwrite(blk, file_offset, length, s->bat, 0);
253
if (ret < 0) {
254
error_setg_errno(errp, -ret, "Failed to write the BAT");
255
goto exit;
256
@@ -XXX,XX +XXX,XX @@ exit:
257
* to create the BAT itself, we will also cause the BAT to be
258
* created.
259
*/
260
-static int vhdx_create_new_region_table(BlockBackend *blk,
261
- uint64_t image_size,
262
- uint32_t block_size,
263
- uint32_t sector_size,
264
- uint32_t log_size,
265
- bool use_zero_blocks,
266
- VHDXImageType type,
267
- uint64_t *metadata_offset,
268
- Error **errp)
269
+static int coroutine_fn
270
+vhdx_create_new_region_table(BlockBackend *blk, uint64_t image_size,
271
+ uint32_t block_size, uint32_t sector_size,
272
+ uint32_t log_size, bool use_zero_blocks,
273
+ VHDXImageType type, uint64_t *metadata_offset,
274
+ Error **errp)
275
{
276
int ret = 0;
277
uint32_t offset = 0;
278
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_new_region_table(BlockBackend *blk,
279
}
280
281
/* Now write out the region headers to disk */
282
- ret = blk_pwrite(blk, VHDX_REGION_TABLE_OFFSET, VHDX_HEADER_BLOCK_SIZE,
283
- buffer, 0);
284
+ ret = blk_co_pwrite(blk, VHDX_REGION_TABLE_OFFSET, VHDX_HEADER_BLOCK_SIZE,
285
+ buffer, 0);
286
if (ret < 0) {
287
error_setg_errno(errp, -ret, "Failed to write first region table");
288
goto exit;
289
}
290
291
- ret = blk_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, VHDX_HEADER_BLOCK_SIZE,
292
- buffer, 0);
293
+ ret = blk_co_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, VHDX_HEADER_BLOCK_SIZE,
294
+ buffer, 0);
295
if (ret < 0) {
296
error_setg_errno(errp, -ret, "Failed to write second region table");
297
goto exit;
286
--
298
--
287
2.13.6
299
2.41.0
288
289
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The following pattern occurs in the .bdrv_co_create_opts() methods of
3
Mark functions as coroutine_fn when they are only called by other coroutine_fns
4
parallels, qcow, qcow2, qed, vhdx and vpc:
4
and they can suspend. Change calls to co_wrappers to use the non-wrapped
5
functions, which in turn requires adding GRAPH_RDLOCK annotations.
5
6
6
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
qobject_unref(qdict);
8
Message-ID: <20230601115145.196465-11-pbonzini@redhat.com>
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>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
11
---
30
block/parallels.c | 9 ++++-----
12
block/qcow2.h | 33 +++++------
31
block/qcow.c | 9 ++++-----
13
block/qcow2-bitmap.c | 26 +++++----
32
block/qcow2.c | 9 ++++-----
14
block/qcow2-cluster.c | 12 ++--
33
block/qed.c | 9 ++++-----
15
block/qcow2-refcount.c | 130 +++++++++++++++++++++--------------------
34
block/vhdx.c | 9 ++++-----
16
block/qcow2.c | 2 +-
35
block/vpc.c | 9 ++++-----
17
5 files changed, 105 insertions(+), 98 deletions(-)
36
6 files changed, 24 insertions(+), 30 deletions(-)
37
18
38
diff --git a/block/parallels.c b/block/parallels.c
19
diff --git a/block/qcow2.h b/block/qcow2.h
39
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
40
--- a/block/parallels.c
21
--- a/block/qcow2.h
41
+++ b/block/parallels.c
22
+++ b/block/qcow2.h
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
23
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
43
BlockdevCreateOptions *create_options = NULL;
24
44
Error *local_err = NULL;
25
int qcow2_mark_dirty(BlockDriverState *bs);
45
BlockDriverState *bs = NULL;
26
int qcow2_mark_corrupt(BlockDriverState *bs);
46
- QDict *qdict = NULL;
27
-int qcow2_mark_consistent(BlockDriverState *bs);
47
+ QDict *qdict;
28
int qcow2_update_header(BlockDriverState *bs);
48
QObject *qobj;
29
49
Visitor *v;
30
void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
31
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
32
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
33
int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
34
int64_t nb_clusters);
35
-int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size);
36
+int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size);
37
void qcow2_free_clusters(BlockDriverState *bs,
38
int64_t offset, int64_t size,
39
enum qcow2_discard_type type);
40
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
41
42
int qcow2_flush_caches(BlockDriverState *bs);
43
int qcow2_write_caches(BlockDriverState *bs);
44
-int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
45
- BdrvCheckMode fix);
46
+int coroutine_fn qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
47
+ BdrvCheckMode fix);
48
49
void qcow2_process_discards(BlockDriverState *bs, int ret);
50
51
@@ -XXX,XX +XXX,XX @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
52
int64_t size);
53
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
54
int64_t size, bool data_file);
55
-int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
56
- void **refcount_table,
57
- int64_t *refcount_table_size,
58
- int64_t offset, int64_t size);
59
+int coroutine_fn qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
60
+ void **refcount_table,
61
+ int64_t *refcount_table_size,
62
+ int64_t offset, int64_t size);
63
64
int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
65
BlockDriverAmendStatusCB *status_cb,
66
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
67
int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
68
unsigned int *bytes,
69
uint64_t *host_offset, QCowL2Meta **m);
70
-int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
71
- uint64_t offset,
72
- int compressed_size,
73
- uint64_t *host_offset);
74
+int coroutine_fn GRAPH_RDLOCK
75
+qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
76
+ int compressed_size, uint64_t *host_offset);
77
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
78
uint64_t *coffset, int *csize);
79
80
@@ -XXX,XX +XXX,XX @@ void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
81
void qcow2_cache_discard(Qcow2Cache *c, void *table);
82
83
/* qcow2-bitmap.c functions */
84
-int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
85
- void **refcount_table,
86
- int64_t *refcount_table_size);
87
-bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
88
- bool *header_updated, Error **errp);
89
+int coroutine_fn
90
+qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
91
+ void **refcount_table,
92
+ int64_t *refcount_table_size);
93
+bool coroutine_fn GRAPH_RDLOCK
94
+qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, Error **errp);
95
bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
96
Qcow2BitmapInfoList **info_list, Error **errp);
97
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
98
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/block/qcow2-bitmap.c
101
+++ b/block/qcow2-bitmap.c
102
@@ -XXX,XX +XXX,XX @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
103
/* load_bitmap_data
104
* @bitmap_table entries must satisfy specification constraints.
105
* @bitmap must be cleared */
106
-static int load_bitmap_data(BlockDriverState *bs,
107
- const uint64_t *bitmap_table,
108
- uint32_t bitmap_table_size,
109
- BdrvDirtyBitmap *bitmap)
110
+static int coroutine_fn GRAPH_RDLOCK
111
+load_bitmap_data(BlockDriverState *bs, const uint64_t *bitmap_table,
112
+ uint32_t bitmap_table_size, BdrvDirtyBitmap *bitmap)
113
{
114
int ret = 0;
115
BDRVQcow2State *s = bs->opaque;
116
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
117
* already cleared */
118
}
119
} else {
120
- ret = bdrv_pread(bs->file, data_offset, s->cluster_size, buf, 0);
121
+ ret = bdrv_co_pread(bs->file, data_offset, s->cluster_size, buf, 0);
122
if (ret < 0) {
123
goto finish;
124
}
125
@@ -XXX,XX +XXX,XX @@ finish:
126
return ret;
127
}
128
129
-static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
130
- Qcow2Bitmap *bm, Error **errp)
131
+static coroutine_fn GRAPH_RDLOCK
132
+BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
133
+ Qcow2Bitmap *bm, Error **errp)
134
{
50
int ret;
135
int ret;
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
136
uint64_t *bitmap_table = NULL;
52
qdict_put_str(qdict, "file", bs->node_name);
137
@@ -XXX,XX +XXX,XX @@ fail:
53
138
return NULL;
54
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
139
}
55
- qobject_unref(qdict);
140
56
- qdict = qobject_to(QDict, qobj);
141
-int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
57
- if (qdict == NULL) {
142
- void **refcount_table,
58
+ if (!qobj) {
143
- int64_t *refcount_table_size)
59
ret = -EINVAL;
144
+int coroutine_fn
60
goto done;
145
+qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
146
+ void **refcount_table,
147
+ int64_t *refcount_table_size)
148
{
149
int ret;
150
BDRVQcow2State *s = bs->opaque;
151
@@ -XXX,XX +XXX,XX @@ static void set_readonly_helper(gpointer bitmap, gpointer value)
152
* If header_updated is not NULL then it is set appropriately regardless of
153
* the return value.
154
*/
155
-bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
156
- bool *header_updated, Error **errp)
157
+bool coroutine_fn GRAPH_RDLOCK
158
+qcow2_load_dirty_bitmaps(BlockDriverState *bs,
159
+ bool *header_updated, Error **errp)
160
{
161
BDRVQcow2State *s = bs->opaque;
162
Qcow2BitmapList *bm_list;
163
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
164
index XXXXXXX..XXXXXXX 100644
165
--- a/block/qcow2-cluster.c
166
+++ b/block/qcow2-cluster.c
167
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
168
*
169
* Return 0 on success and -errno in error cases
170
*/
171
-int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
172
- uint64_t offset,
173
- int compressed_size,
174
- uint64_t *host_offset)
175
+int coroutine_fn GRAPH_RDLOCK
176
+qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
177
+ int compressed_size, uint64_t *host_offset)
178
{
179
BDRVQcow2State *s = bs->opaque;
180
int l2_index, ret;
181
@@ -XXX,XX +XXX,XX @@ fail:
182
* all clusters in the same L2 slice) and returns the number of zeroed
183
* clusters.
184
*/
185
-static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
186
- uint64_t nb_clusters, int flags)
187
+static int coroutine_fn
188
+zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
189
+ uint64_t nb_clusters, int flags)
190
{
191
BDRVQcow2State *s = bs->opaque;
192
uint64_t *l2_slice;
193
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
194
index XXXXXXX..XXXXXXX 100644
195
--- a/block/qcow2-refcount.c
196
+++ b/block/qcow2-refcount.c
197
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offs
198
199
/* only used to allocate compressed sectors. We try to allocate
200
contiguous sectors. size must be <= cluster_size */
201
-int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size)
202
+int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size)
203
{
204
BDRVQcow2State *s = bs->opaque;
205
int64_t offset;
206
@@ -XXX,XX +XXX,XX @@ static int realloc_refcount_array(BDRVQcow2State *s, void **array,
207
*
208
* Modifies the number of errors in res.
209
*/
210
-int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
211
- void **refcount_table,
212
- int64_t *refcount_table_size,
213
- int64_t offset, int64_t size)
214
+int coroutine_fn GRAPH_RDLOCK
215
+qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
216
+ void **refcount_table,
217
+ int64_t *refcount_table_size,
218
+ int64_t offset, int64_t size)
219
{
220
BDRVQcow2State *s = bs->opaque;
221
uint64_t start, last, cluster_offset, k, refcount;
222
@@ -XXX,XX +XXX,XX @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
223
return 0;
61
}
224
}
62
225
63
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
226
- file_len = bdrv_getlength(bs->file->bs);
64
+ v = qobject_input_visitor_new_keyval(qobj);
227
+ file_len = bdrv_co_getlength(bs->file->bs);
65
+ qobject_unref(qobj);
228
if (file_len < 0) {
66
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
229
return file_len;
67
visit_free(v);
230
}
68
231
@@ -XXX,XX +XXX,XX @@ enum {
69
diff --git a/block/qcow.c b/block/qcow.c
232
*
70
index XXXXXXX..XXXXXXX 100644
233
* On failure in-memory @l2_table may be modified.
71
--- a/block/qcow.c
234
*/
72
+++ b/block/qcow.c
235
-static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
73
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
236
- uint64_t l2_offset,
74
{
237
- uint64_t *l2_table, int l2_index, bool active,
75
BlockdevCreateOptions *create_options = NULL;
238
- bool *metadata_overlap)
76
BlockDriverState *bs = NULL;
239
+static int coroutine_fn GRAPH_RDLOCK
77
- QDict *qdict = NULL;
240
+fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
78
+ QDict *qdict;
241
+ uint64_t l2_offset, uint64_t *l2_table,
79
QObject *qobj;
242
+ int l2_index, bool active,
80
Visitor *v;
243
+ bool *metadata_overlap)
81
const char *val;
244
{
82
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
245
BDRVQcow2State *s = bs->opaque;
83
qdict_put_str(qdict, "file", bs->node_name);
246
int ret;
84
247
@@ -XXX,XX +XXX,XX @@ static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
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;
248
goto fail;
92
}
249
}
93
250
94
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
251
- ret = bdrv_pwrite_sync(bs->file, l2e_offset, l2_entry_size(s),
95
+ v = qobject_input_visitor_new_keyval(qobj);
252
- &l2_table[idx], 0);
96
+ qobject_unref(qobj);
253
+ ret = bdrv_co_pwrite_sync(bs->file, l2e_offset, l2_entry_size(s),
97
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
254
+ &l2_table[idx], 0);
98
visit_free(v);
255
if (ret < 0) {
99
256
fprintf(stderr, "ERROR: Failed to overwrite L2 "
257
"table entry: %s\n", strerror(-ret));
258
@@ -XXX,XX +XXX,XX @@ fail:
259
* Returns the number of errors found by the checks or -errno if an internal
260
* error occurred.
261
*/
262
-static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
263
- void **refcount_table,
264
- int64_t *refcount_table_size, int64_t l2_offset,
265
- int flags, BdrvCheckMode fix, bool active)
266
+static int coroutine_fn GRAPH_RDLOCK
267
+check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
268
+ void **refcount_table,
269
+ int64_t *refcount_table_size, int64_t l2_offset,
270
+ int flags, BdrvCheckMode fix, bool active)
271
{
272
BDRVQcow2State *s = bs->opaque;
273
uint64_t l2_entry, l2_bitmap;
274
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
275
bool metadata_overlap;
276
277
/* Read L2 table from disk */
278
- ret = bdrv_pread(bs->file, l2_offset, l2_size_bytes, l2_table, 0);
279
+ ret = bdrv_co_pread(bs->file, l2_offset, l2_size_bytes, l2_table, 0);
280
if (ret < 0) {
281
fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
282
res->check_errors++;
283
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
284
* Returns the number of errors found by the checks or -errno if an internal
285
* error occurred.
286
*/
287
-static int check_refcounts_l1(BlockDriverState *bs,
288
- BdrvCheckResult *res,
289
- void **refcount_table,
290
- int64_t *refcount_table_size,
291
- int64_t l1_table_offset, int l1_size,
292
- int flags, BdrvCheckMode fix, bool active)
293
+static int coroutine_fn GRAPH_RDLOCK
294
+check_refcounts_l1(BlockDriverState *bs, BdrvCheckResult *res,
295
+ void **refcount_table, int64_t *refcount_table_size,
296
+ int64_t l1_table_offset, int l1_size,
297
+ int flags, BdrvCheckMode fix, bool active)
298
{
299
BDRVQcow2State *s = bs->opaque;
300
size_t l1_size_bytes = l1_size * L1E_SIZE;
301
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l1(BlockDriverState *bs,
302
}
303
304
/* Read L1 table entries from disk */
305
- ret = bdrv_pread(bs->file, l1_table_offset, l1_size_bytes, l1_table, 0);
306
+ ret = bdrv_co_pread(bs->file, l1_table_offset, l1_size_bytes, l1_table, 0);
307
if (ret < 0) {
308
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
309
res->check_errors++;
310
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l1(BlockDriverState *bs,
311
* have been already detected and sufficiently signaled by the calling function
312
* (qcow2_check_refcounts) by the time this function is called).
313
*/
314
-static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
315
- BdrvCheckMode fix)
316
+static int coroutine_fn GRAPH_RDLOCK
317
+check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
318
{
319
BDRVQcow2State *s = bs->opaque;
320
uint64_t *l2_table = qemu_blockalign(bs, s->cluster_size);
321
@@ -XXX,XX +XXX,XX @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
322
}
323
}
324
325
- ret = bdrv_pread(bs->file, l2_offset, s->l2_size * l2_entry_size(s),
326
- l2_table, 0);
327
+ ret = bdrv_co_pread(bs->file, l2_offset, s->l2_size * l2_entry_size(s),
328
+ l2_table, 0);
329
if (ret < 0) {
330
fprintf(stderr, "ERROR: Could not read L2 table: %s\n",
331
strerror(-ret));
332
@@ -XXX,XX +XXX,XX @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
333
goto fail;
334
}
335
336
- ret = bdrv_pwrite(bs->file, l2_offset, s->cluster_size, l2_table,
337
- 0);
338
+ ret = bdrv_co_pwrite(bs->file, l2_offset, s->cluster_size, l2_table, 0);
339
if (ret < 0) {
340
fprintf(stderr, "ERROR: Could not write L2 table: %s\n",
341
strerror(-ret));
342
@@ -XXX,XX +XXX,XX @@ fail:
343
* Checks consistency of refblocks and accounts for each refblock in
344
* *refcount_table.
345
*/
346
-static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
347
- BdrvCheckMode fix, bool *rebuild,
348
- void **refcount_table, int64_t *nb_clusters)
349
+static int coroutine_fn GRAPH_RDLOCK
350
+check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
351
+ BdrvCheckMode fix, bool *rebuild,
352
+ void **refcount_table, int64_t *nb_clusters)
353
{
354
BDRVQcow2State *s = bs->opaque;
355
int64_t i, size;
356
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
357
goto resize_fail;
358
}
359
360
- ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
361
- PREALLOC_MODE_OFF, 0, &local_err);
362
+ ret = bdrv_co_truncate(bs->file, offset + s->cluster_size, false,
363
+ PREALLOC_MODE_OFF, 0, &local_err);
364
if (ret < 0) {
365
error_report_err(local_err);
366
goto resize_fail;
367
}
368
- size = bdrv_getlength(bs->file->bs);
369
+ size = bdrv_co_getlength(bs->file->bs);
370
if (size < 0) {
371
ret = size;
372
goto resize_fail;
373
@@ -XXX,XX +XXX,XX @@ resize_fail:
374
/*
375
* Calculates an in-memory refcount table.
376
*/
377
-static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
378
- BdrvCheckMode fix, bool *rebuild,
379
- void **refcount_table, int64_t *nb_clusters)
380
+static int coroutine_fn GRAPH_RDLOCK
381
+calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
382
+ BdrvCheckMode fix, bool *rebuild,
383
+ void **refcount_table, int64_t *nb_clusters)
384
{
385
BDRVQcow2State *s = bs->opaque;
386
int64_t i;
387
@@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
388
* Compares the actual reference count for each cluster in the image against the
389
* refcount as reported by the refcount structures on-disk.
390
*/
391
-static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
392
- BdrvCheckMode fix, bool *rebuild,
393
- int64_t *highest_cluster,
394
- void *refcount_table, int64_t nb_clusters)
395
+static void coroutine_fn
396
+compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
397
+ BdrvCheckMode fix, bool *rebuild,
398
+ int64_t *highest_cluster,
399
+ void *refcount_table, int64_t nb_clusters)
400
{
401
BDRVQcow2State *s = bs->opaque;
402
int64_t i;
403
@@ -XXX,XX +XXX,XX @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
404
* Return whether the on-disk reftable array was resized (true/false),
405
* or -errno on error.
406
*/
407
-static int rebuild_refcounts_write_refblocks(
408
+static int coroutine_fn GRAPH_RDLOCK
409
+rebuild_refcounts_write_refblocks(
410
BlockDriverState *bs, void **refcount_table, int64_t *nb_clusters,
411
int64_t first_cluster, int64_t end_cluster,
412
uint64_t **on_disk_reftable_ptr, uint32_t *on_disk_reftable_entries_ptr,
413
@@ -XXX,XX +XXX,XX @@ static int rebuild_refcounts_write_refblocks(
414
on_disk_refblock = (void *)((char *) *refcount_table +
415
refblock_index * s->cluster_size);
416
417
- ret = bdrv_pwrite(bs->file, refblock_offset, s->cluster_size,
418
- on_disk_refblock, 0);
419
+ ret = bdrv_co_pwrite(bs->file, refblock_offset, s->cluster_size,
420
+ on_disk_refblock, 0);
421
if (ret < 0) {
422
error_setg_errno(errp, -ret, "ERROR writing refblock");
423
return ret;
424
@@ -XXX,XX +XXX,XX @@ static int rebuild_refcounts_write_refblocks(
425
* On success, the old refcount structure is leaked (it will be covered by the
426
* new refcount structure).
427
*/
428
-static int rebuild_refcount_structure(BlockDriverState *bs,
429
- BdrvCheckResult *res,
430
- void **refcount_table,
431
- int64_t *nb_clusters,
432
- Error **errp)
433
+static int coroutine_fn GRAPH_RDLOCK
434
+rebuild_refcount_structure(BlockDriverState *bs, BdrvCheckResult *res,
435
+ void **refcount_table, int64_t *nb_clusters,
436
+ Error **errp)
437
{
438
BDRVQcow2State *s = bs->opaque;
439
int64_t reftable_offset = -1;
440
@@ -XXX,XX +XXX,XX @@ static int rebuild_refcount_structure(BlockDriverState *bs,
441
}
442
443
assert(reftable_length < INT_MAX);
444
- ret = bdrv_pwrite(bs->file, reftable_offset, reftable_length,
445
- on_disk_reftable, 0);
446
+ ret = bdrv_co_pwrite(bs->file, reftable_offset, reftable_length,
447
+ on_disk_reftable, 0);
448
if (ret < 0) {
449
error_setg_errno(errp, -ret, "ERROR writing reftable");
450
goto fail;
451
@@ -XXX,XX +XXX,XX @@ static int rebuild_refcount_structure(BlockDriverState *bs,
452
reftable_offset_and_clusters.reftable_offset = cpu_to_be64(reftable_offset);
453
reftable_offset_and_clusters.reftable_clusters =
454
cpu_to_be32(reftable_clusters);
455
- ret = bdrv_pwrite_sync(bs->file,
456
- offsetof(QCowHeader, refcount_table_offset),
457
- sizeof(reftable_offset_and_clusters),
458
- &reftable_offset_and_clusters, 0);
459
+ ret = bdrv_co_pwrite_sync(bs->file,
460
+ offsetof(QCowHeader, refcount_table_offset),
461
+ sizeof(reftable_offset_and_clusters),
462
+ &reftable_offset_and_clusters, 0);
463
if (ret < 0) {
464
error_setg_errno(errp, -ret, "ERROR setting reftable");
465
goto fail;
466
@@ -XXX,XX +XXX,XX @@ fail:
467
* Returns 0 if no errors are found, the number of errors in case the image is
468
* detected as corrupted, and -errno when an internal error occurred.
469
*/
470
-int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
471
- BdrvCheckMode fix)
472
+int coroutine_fn GRAPH_RDLOCK
473
+qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
474
{
475
BDRVQcow2State *s = bs->opaque;
476
BdrvCheckResult pre_compare_res;
477
@@ -XXX,XX +XXX,XX @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
478
bool rebuild = false;
479
int ret;
480
481
- size = bdrv_getlength(bs->file->bs);
482
+ size = bdrv_co_getlength(bs->file->bs);
483
if (size < 0) {
484
res->check_errors++;
485
return size;
486
@@ -XXX,XX +XXX,XX @@ done:
487
return ret;
488
}
489
490
-static int64_t get_refblock_offset(BlockDriverState *bs, uint64_t offset)
491
+static int64_t coroutine_fn get_refblock_offset(BlockDriverState *bs,
492
+ uint64_t offset)
493
{
494
BDRVQcow2State *s = bs->opaque;
495
uint32_t index = offset_to_reftable_index(s, offset);
496
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
497
return -EIO;
498
}
499
500
-int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs)
501
+int coroutine_fn GRAPH_RDLOCK
502
+qcow2_detect_metadata_preallocation(BlockDriverState *bs)
503
{
504
BDRVQcow2State *s = bs->opaque;
505
int64_t i, end_cluster, cluster_count = 0, threshold;
100
diff --git a/block/qcow2.c b/block/qcow2.c
506
diff --git a/block/qcow2.c b/block/qcow2.c
101
index XXXXXXX..XXXXXXX 100644
507
index XXXXXXX..XXXXXXX 100644
102
--- a/block/qcow2.c
508
--- a/block/qcow2.c
103
+++ b/block/qcow2.c
509
+++ b/block/qcow2.c
104
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
510
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_corrupt(BlockDriverState *bs)
105
Error **errp)
511
* Marks the image as consistent, i.e., unsets the corrupt bit, and flushes
106
{
512
* before if necessary.
107
BlockdevCreateOptions *create_options = NULL;
513
*/
108
- QDict *qdict = NULL;
514
-int qcow2_mark_consistent(BlockDriverState *bs)
109
+ QDict *qdict;
515
+static int coroutine_fn qcow2_mark_consistent(BlockDriverState *bs)
110
QObject *qobj;
516
{
111
Visitor *v;
517
BDRVQcow2State *s = bs->opaque;
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
518
224
--
519
--
225
2.13.6
520
2.41.0
226
227
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
There are numerous QDict functions that have been introduced for and are
3
bdrv_co_getlength was recently introduced, with bdrv_getlength becoming
4
used only by the block layer. Move their declarations into an own
4
a wrapper for use in unknown context. Switch to bdrv_co_getlength when
5
header file to reflect that.
5
possible.
6
6
7
While qdict_extract_subqdict() is in fact used outside of the block
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
layer (in util/qemu-config.c), it is still a function related very
8
Message-ID: <20230601115145.196465-12-pbonzini@redhat.com>
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>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
11
---
22
include/block/qdict.h | 32 ++++++++++++++++++++++++++++++++
12
block/io.c | 10 +++++-----
23
include/qapi/qmp/qdict.h | 17 -----------------
13
block/parallels.c | 4 ++--
24
block.c | 1 +
14
block/qcow.c | 6 +++---
25
block/gluster.c | 1 +
15
block/vmdk.c | 4 ++--
26
block/iscsi.c | 1 +
16
4 files changed, 12 insertions(+), 12 deletions(-)
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
17
51
diff --git a/include/block/qdict.h b/include/block/qdict.h
18
diff --git a/block/io.c b/block/io.c
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
19
index XXXXXXX..XXXXXXX 100644
91
--- a/include/qapi/qmp/qdict.h
20
--- a/block/io.c
92
+++ b/include/qapi/qmp/qdict.h
21
+++ b/block/io.c
93
@@ -XXX,XX +XXX,XX @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key,
22
@@ -XXX,XX +XXX,XX @@ bdrv_aligned_preadv(BdrvChild *child, BdrvTrackedRequest *req,
94
bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value);
23
}
95
const char *qdict_get_try_str(const QDict *qdict, const char *key);
24
96
25
/* Forward the request to the BlockDriver, possibly fragmenting it */
97
-void qdict_copy_default(QDict *dst, QDict *src, const char *key);
26
- total_bytes = bdrv_getlength(bs);
98
-void qdict_set_default_str(QDict *dst, const char *key, const char *val);
27
+ total_bytes = bdrv_co_getlength(bs);
99
-
28
if (total_bytes < 0) {
100
QDict *qdict_clone_shallow(const QDict *src);
29
ret = total_bytes;
101
-void qdict_flatten(QDict *qdict);
30
goto out;
102
-
31
@@ -XXX,XX +XXX,XX @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
103
-void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
32
assert(pnum);
104
-void qdict_array_split(QDict *src, QList **dst);
33
assert_bdrv_graph_readable();
105
-int qdict_array_entries(QDict *src, const char *subqdict);
34
*pnum = 0;
106
-QObject *qdict_crumple(const QDict *src, Error **errp);
35
- total_size = bdrv_getlength(bs);
107
-
36
+ total_size = bdrv_co_getlength(bs);
108
-void qdict_join(QDict *dest, QDict *src, bool overwrite);
37
if (total_size < 0) {
109
-
38
ret = total_size;
110
-typedef struct QDictRenames {
39
goto early_out;
111
- const char *from;
40
@@ -XXX,XX +XXX,XX @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
112
- const char *to;
41
bytes = n;
113
-} QDictRenames;
42
}
114
-bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
43
115
44
- /* Must be non-NULL or bdrv_getlength() would have failed */
116
#endif /* QDICT_H */
45
+ /* Must be non-NULL or bdrv_co_getlength() would have failed */
117
diff --git a/block.c b/block.c
46
assert(bs->drv);
118
index XXXXXXX..XXXXXXX 100644
47
has_filtered_child = bdrv_filter_child(bs);
119
--- a/block.c
48
if (!bs->drv->bdrv_co_block_status && !has_filtered_child) {
120
+++ b/block.c
49
@@ -XXX,XX +XXX,XX @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
121
@@ -XXX,XX +XXX,XX @@
50
if (!cow_bs) {
122
#include "block/block_int.h"
51
ret |= BDRV_BLOCK_ZERO;
123
#include "block/blockjob.h"
52
} else if (want_zero) {
124
#include "block/nbd.h"
53
- int64_t size2 = bdrv_getlength(cow_bs);
125
+#include "block/qdict.h"
54
+ int64_t size2 = bdrv_co_getlength(cow_bs);
126
#include "qemu/error-report.h"
55
127
#include "module_block.h"
56
if (size2 >= 0 && offset >= size2) {
128
#include "qemu/module.h"
57
ret |= BDRV_BLOCK_ZERO;
129
diff --git a/block/gluster.c b/block/gluster.c
58
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
130
index XXXXXXX..XXXXXXX 100644
59
return ret;
131
--- a/block/gluster.c
60
}
132
+++ b/block/gluster.c
61
133
@@ -XXX,XX +XXX,XX @@
62
- old_size = bdrv_getlength(bs);
134
#include "qemu/osdep.h"
63
+ old_size = bdrv_co_getlength(bs);
135
#include <glusterfs/api/glfs.h>
64
if (old_size < 0) {
136
#include "block/block_int.h"
65
error_setg_errno(errp, -old_size, "Failed to get old image size");
137
+#include "block/qdict.h"
66
return old_size;
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
67
diff --git a/block/parallels.c b/block/parallels.c
178
index XXXXXXX..XXXXXXX 100644
68
index XXXXXXX..XXXXXXX 100644
179
--- a/block/parallels.c
69
--- a/block/parallels.c
180
+++ b/block/parallels.c
70
+++ b/block/parallels.c
181
@@ -XXX,XX +XXX,XX @@
71
@@ -XXX,XX +XXX,XX @@ allocate_clusters(BlockDriverState *bs, int64_t sector_num,
182
#include "qemu/osdep.h"
72
assert(idx < s->bat_size && idx + to_allocate <= s->bat_size);
183
#include "qapi/error.h"
73
184
#include "block/block_int.h"
74
space = to_allocate * s->tracks;
185
+#include "block/qdict.h"
75
- len = bdrv_getlength(bs->file->bs);
186
#include "sysemu/block-backend.h"
76
+ len = bdrv_co_getlength(bs->file->bs);
187
#include "qemu/module.h"
77
if (len < 0) {
188
#include "qemu/option.h"
78
return len;
79
}
80
@@ -XXX,XX +XXX,XX @@ parallels_check_outside_image(BlockDriverState *bs, BdrvCheckResult *res,
81
uint32_t i;
82
int64_t off, high_off, size;
83
84
- size = bdrv_getlength(bs->file->bs);
85
+ size = bdrv_co_getlength(bs->file->bs);
86
if (size < 0) {
87
res->check_errors++;
88
return size;
189
diff --git a/block/qcow.c b/block/qcow.c
89
diff --git a/block/qcow.c b/block/qcow.c
190
index XXXXXXX..XXXXXXX 100644
90
index XXXXXXX..XXXXXXX 100644
191
--- a/block/qcow.c
91
--- a/block/qcow.c
192
+++ b/block/qcow.c
92
+++ b/block/qcow.c
193
@@ -XXX,XX +XXX,XX @@
93
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
194
#include "qapi/error.h"
94
if (!allocate)
195
#include "qemu/error-report.h"
95
return 0;
196
#include "block/block_int.h"
96
/* allocate a new l2 entry */
197
+#include "block/qdict.h"
97
- l2_offset = bdrv_getlength(bs->file->bs);
198
#include "sysemu/block-backend.h"
98
+ l2_offset = bdrv_co_getlength(bs->file->bs);
199
#include "qemu/module.h"
99
if (l2_offset < 0) {
200
#include "qemu/option.h"
100
return l2_offset;
201
diff --git a/block/qcow2.c b/block/qcow2.c
101
}
102
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
103
if (decompress_cluster(bs, cluster_offset) < 0) {
104
return -EIO;
105
}
106
- cluster_offset = bdrv_getlength(bs->file->bs);
107
+ cluster_offset = bdrv_co_getlength(bs->file->bs);
108
if ((int64_t) cluster_offset < 0) {
109
return cluster_offset;
110
}
111
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
112
return ret;
113
}
114
} else {
115
- cluster_offset = bdrv_getlength(bs->file->bs);
116
+ cluster_offset = bdrv_co_getlength(bs->file->bs);
117
if ((int64_t) cluster_offset < 0) {
118
return cluster_offset;
119
}
120
diff --git a/block/vmdk.c b/block/vmdk.c
202
index XXXXXXX..XXXXXXX 100644
121
index XXXXXXX..XXXXXXX 100644
203
--- a/block/qcow2.c
122
--- a/block/vmdk.c
204
+++ b/block/qcow2.c
123
+++ b/block/vmdk.c
205
@@ -XXX,XX +XXX,XX @@
124
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
206
125
int64_t length;
207
#include "qemu/osdep.h"
126
208
#include "block/block_int.h"
127
for (i = 0; i < s->num_extents; i++) {
209
+#include "block/qdict.h"
128
- length = bdrv_getlength(s->extents[i].file->bs);
210
#include "sysemu/block-backend.h"
129
+ length = bdrv_co_getlength(s->extents[i].file->bs);
211
#include "qemu/module.h"
130
if (length < 0) {
212
#include <zlib.h>
131
return length;
213
diff --git a/block/qed.c b/block/qed.c
132
}
214
index XXXXXXX..XXXXXXX 100644
133
@@ -XXX,XX +XXX,XX @@ vmdk_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix)
215
--- a/block/qed.c
134
break;
216
+++ b/block/qed.c
135
}
217
@@ -XXX,XX +XXX,XX @@
136
if (ret == VMDK_OK) {
218
*/
137
- int64_t extent_len = bdrv_getlength(extent->file->bs);
219
138
+ int64_t extent_len = bdrv_co_getlength(extent->file->bs);
220
#include "qemu/osdep.h"
139
if (extent_len < 0) {
221
+#include "block/qdict.h"
140
fprintf(stderr,
222
#include "qapi/error.h"
141
"ERROR: could not get extent file length for sector %"
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
--
142
--
404
2.13.6
143
2.41.0
405
406
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
3
bdrv_co_debug_event was recently introduced, with bdrv_debug_event
4
becoming a wrapper for use in unknown context. Because most of the
5
time bdrv_debug_event is used on a BdrvChild via the wrapper macro
6
BLKDBG_EVENT, introduce a similar macro BLKDBG_CO_EVENT that calls
7
bdrv_co_debug_event, and switch whenever possible.
8
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Message-ID: <20230601115145.196465-13-pbonzini@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
13
---
7
include/block/qdict.h | 3 ++-
14
include/block/block-io.h | 7 +++++++
8
block/nbd.c | 7 ++-----
15
block/io.c | 4 ++--
9
block/nfs.c | 7 ++-----
16
block/qcow.c | 24 ++++++++++++------------
10
block/parallels.c | 7 ++-----
17
block/qcow2-cluster.c | 12 ++++++------
11
block/qcow.c | 7 ++-----
18
block/qcow2-refcount.c | 4 ++--
12
block/qcow2.c | 7 ++-----
19
block/qcow2.c | 18 +++++++++---------
13
block/qed.c | 7 ++-----
20
block/qed-table.c | 6 +++---
14
block/rbd.c | 7 ++-----
21
block/qed.c | 8 ++++----
15
block/sheepdog.c | 14 ++++----------
22
block/raw-format.c | 4 ++--
16
block/ssh.c | 7 ++-----
23
block/vmdk.c | 24 ++++++++++++------------
17
block/vhdx.c | 7 ++-----
24
10 files changed, 59 insertions(+), 52 deletions(-)
18
block/vpc.c | 7 ++-----
19
qobject/block-qdict.c | 28 +++++++++++++++++++++++++++-
20
13 files changed, 53 insertions(+), 62 deletions(-)
21
25
22
diff --git a/include/block/qdict.h b/include/block/qdict.h
26
diff --git a/include/block/block-io.h b/include/block/block-io.h
23
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/qdict.h
28
--- a/include/block/block-io.h
25
+++ b/include/block/qdict.h
29
+++ b/include/block/block-io.h
26
@@ -XXX,XX +XXX,XX @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
30
@@ -XXX,XX +XXX,XX @@ bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event);
27
void qdict_array_split(QDict *src, QList **dst);
31
void co_wrapper_mixed_bdrv_rdlock
28
int qdict_array_entries(QDict *src, const char *subqdict);
32
bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event);
29
QObject *qdict_crumple(const QDict *src, Error **errp);
33
30
-QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp);
34
+#define BLKDBG_CO_EVENT(child, evt) \
31
void qdict_flatten(QDict *qdict);
35
+ do { \
32
36
+ if (child) { \
33
typedef struct QDictRenames {
37
+ bdrv_co_debug_event(child->bs, evt); \
34
@@ -XXX,XX +XXX,XX @@ typedef struct QDictRenames {
38
+ } \
35
} QDictRenames;
39
+ } while (0)
36
bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
40
+
37
41
#define BLKDBG_EVENT(child, evt) \
38
+Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict,
42
do { \
39
+ Error **errp);
43
if (child) { \
40
#endif
44
diff --git a/block/io.c b/block/io.c
41
diff --git a/block/nbd.c b/block/nbd.c
45
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
46
--- a/block/io.c
43
--- a/block/nbd.c
47
+++ b/block/io.c
44
+++ b/block/nbd.c
48
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
45
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
49
}
46
{
50
47
SocketAddress *saddr = NULL;
51
/* Write back cached data to the OS even with cache=unsafe */
48
QDict *addr = NULL;
52
- BLKDBG_EVENT(primary_child, BLKDBG_FLUSH_TO_OS);
49
- QObject *crumpled_addr = NULL;
53
+ BLKDBG_CO_EVENT(primary_child, BLKDBG_FLUSH_TO_OS);
50
Visitor *iv = NULL;
54
if (bs->drv->bdrv_co_flush_to_os) {
51
Error *local_err = NULL;
55
ret = bs->drv->bdrv_co_flush_to_os(bs);
52
56
if (ret < 0) {
53
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
57
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
54
goto done;
58
goto flush_children;
55
}
59
}
56
60
57
- crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp);
61
- BLKDBG_EVENT(primary_child, BLKDBG_FLUSH_TO_DISK);
58
- if (!crumpled_addr) {
62
+ BLKDBG_CO_EVENT(primary_child, BLKDBG_FLUSH_TO_DISK);
59
+ iv = qobject_input_visitor_new_flat_confused(addr, errp);
63
if (!bs->drv) {
60
+ if (!iv) {
64
/* bs->drv->bdrv_co_flush() might have ejected the BDS
61
goto done;
65
* (even in case of apparent success) */
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
66
diff --git a/block/qcow.c b/block/qcow.c
133
index XXXXXXX..XXXXXXX 100644
67
index XXXXXXX..XXXXXXX 100644
134
--- a/block/qcow.c
68
--- a/block/qcow.c
135
+++ b/block/qcow.c
69
+++ b/block/qcow.c
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
70
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
137
BlockdevCreateOptions *create_options = NULL;
71
/* update the L1 entry */
138
BlockDriverState *bs = NULL;
72
s->l1_table[l1_index] = l2_offset;
139
QDict *qdict;
73
tmp = cpu_to_be64(l2_offset);
140
- QObject *qobj;
74
- BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
141
Visitor *v;
75
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L1_UPDATE);
142
const char *val;
76
ret = bdrv_co_pwrite_sync(bs->file,
143
Error *local_err = NULL;
77
s->l1_table_offset + l1_index * sizeof(tmp),
144
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
78
sizeof(tmp), &tmp, 0);
145
qdict_put_str(qdict, "driver", "qcow");
79
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
146
qdict_put_str(qdict, "file", bs->node_name);
80
}
147
81
}
148
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
82
l2_table = s->l2_cache + (min_index << s->l2_bits);
149
- if (!qobj) {
83
- BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
150
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
84
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L2_LOAD);
151
+ if (!v) {
85
if (new_l2_table) {
152
ret = -EINVAL;
86
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
153
goto fail;
87
ret = bdrv_co_pwrite_sync(bs->file, l2_offset,
154
}
88
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
155
89
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
156
- v = qobject_input_visitor_new_keyval(qobj);
90
if (!allocate)
157
- qobject_unref(qobj);
91
return 0;
158
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
92
- BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
159
visit_free(v);
93
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
94
assert(QEMU_IS_ALIGNED(n_start | n_end, BDRV_SECTOR_SIZE));
95
/* allocate a new cluster */
96
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
97
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
98
}
99
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
100
/* write the cluster content */
101
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
102
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
103
ret = bdrv_co_pwrite(bs->file, cluster_offset, s->cluster_size,
104
s->cluster_cache, 0);
105
if (ret < 0) {
106
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
107
NULL) < 0) {
108
return -EIO;
109
}
110
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
111
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
112
ret = bdrv_co_pwrite(bs->file, cluster_offset + i,
113
BDRV_SECTOR_SIZE,
114
s->cluster_data, 0);
115
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
116
tmp = cpu_to_be64(cluster_offset);
117
l2_table[l2_index] = tmp;
118
if (allocate == 2) {
119
- BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
120
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
121
} else {
122
- BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
123
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L2_UPDATE);
124
}
125
ret = bdrv_co_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
126
sizeof(tmp), &tmp, 0);
127
@@ -XXX,XX +XXX,XX @@ decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
128
if (s->cluster_cache_offset != coffset) {
129
csize = cluster_offset >> (63 - s->cluster_bits);
130
csize &= (s->cluster_size - 1);
131
- BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
132
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
133
ret = bdrv_co_pread(bs->file, coffset, csize, s->cluster_data, 0);
134
if (ret < 0)
135
return -1;
136
@@ -XXX,XX +XXX,XX @@ qcow_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
137
/* read from the base image */
138
qemu_co_mutex_unlock(&s->lock);
139
/* qcow2 emits this on bs->file instead of bs->backing */
140
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
141
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
142
ret = bdrv_co_pread(bs->backing, offset, n, buf, 0);
143
qemu_co_mutex_lock(&s->lock);
144
if (ret < 0) {
145
@@ -XXX,XX +XXX,XX @@ qcow_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
146
break;
147
}
148
qemu_co_mutex_unlock(&s->lock);
149
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
150
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
151
ret = bdrv_co_pread(bs->file, cluster_offset + offset_in_cluster,
152
n, buf, 0);
153
qemu_co_mutex_lock(&s->lock);
154
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
155
}
156
157
qemu_co_mutex_unlock(&s->lock);
158
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
159
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
160
ret = bdrv_co_pwrite(bs->file, cluster_offset + offset_in_cluster,
161
n, buf, 0);
162
qemu_co_mutex_lock(&s->lock);
163
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
164
}
165
cluster_offset &= s->cluster_offset_mask;
166
167
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
168
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
169
ret = bdrv_co_pwrite(bs->file, cluster_offset, out_len, out_buf, 0);
170
if (ret < 0) {
171
goto fail;
172
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
173
index XXXXXXX..XXXXXXX 100644
174
--- a/block/qcow2-cluster.c
175
+++ b/block/qcow2-cluster.c
176
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs,
177
fprintf(stderr, "shrink l1_table from %d to %d\n", s->l1_size, new_l1_size);
178
#endif
179
180
- BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE);
181
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE);
182
ret = bdrv_co_pwrite_zeroes(bs->file,
183
s->l1_table_offset + new_l1_size * L1E_SIZE,
184
(s->l1_size - new_l1_size) * L1E_SIZE, 0);
185
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs,
186
goto fail;
187
}
188
189
- BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_FREE_L2_CLUSTERS);
190
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L1_SHRINK_FREE_L2_CLUSTERS);
191
for (i = s->l1_size - 1; i > new_l1_size - 1; i--) {
192
if ((s->l1_table[i] & L1E_OFFSET_MASK) == 0) {
193
continue;
194
@@ -XXX,XX +XXX,XX @@ do_perform_cow_read(BlockDriverState *bs, uint64_t src_cluster_offset,
195
return 0;
196
}
197
198
- BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
199
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_COW_READ);
200
201
if (!bs->drv) {
202
return -ENOMEDIUM;
203
@@ -XXX,XX +XXX,XX @@ do_perform_cow_write(BlockDriverState *bs, uint64_t cluster_offset,
204
return ret;
205
}
206
207
- BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
208
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_COW_WRITE);
209
ret = bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_cluster,
210
qiov->size, qiov, 0);
211
if (ret < 0) {
212
@@ -XXX,XX +XXX,XX @@ qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
213
214
/* compressed clusters never have the copied flag */
215
216
- BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
217
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
218
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
219
set_l2_entry(s, l2_slice, l2_index, cluster_offset);
220
if (has_subclusters(s)) {
221
@@ -XXX,XX +XXX,XX @@ perform_cow(BlockDriverState *bs, QCowL2Meta *m)
222
/* NOTE: we have a write_aio blkdebug event here followed by
223
* a cow_write one in do_perform_cow_write(), but there's only
224
* one single I/O operation */
225
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
226
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
227
ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
228
} else {
229
/* If there's no guest data then write both COW regions separately */
230
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
231
index XXXXXXX..XXXXXXX 100644
232
--- a/block/qcow2-refcount.c
233
+++ b/block/qcow2-refcount.c
234
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_refcount_init(BlockDriverState *bs)
235
ret = -ENOMEM;
236
goto fail;
237
}
238
- BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
239
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
240
ret = bdrv_co_pread(bs->file, s->refcount_table_offset,
241
refcount_table_size2, s->refcount_table, 0);
242
if (ret < 0) {
243
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int si
244
size_t free_in_cluster;
245
int ret;
246
247
- BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_BYTES);
248
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_BYTES);
249
assert(size > 0 && size <= s->cluster_size);
250
assert(!s->free_byte_offset || offset_into_cluster(s, s->free_byte_offset));
160
251
161
diff --git a/block/qcow2.c b/block/qcow2.c
252
diff --git a/block/qcow2.c b/block/qcow2.c
162
index XXXXXXX..XXXXXXX 100644
253
index XXXXXXX..XXXXXXX 100644
163
--- a/block/qcow2.c
254
--- a/block/qcow2.c
164
+++ b/block/qcow2.c
255
+++ b/block/qcow2.c
165
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
256
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_encrypted(BlockDriverState *bs,
257
return -ENOMEM;
258
}
259
260
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
261
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
262
ret = bdrv_co_pread(s->data_file, host_offset, bytes, buf, 0);
263
if (ret < 0) {
264
goto fail;
265
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_task(BlockDriverState *bs, QCow2SubclusterType subc_type,
266
case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
267
assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */
268
269
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
270
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
271
return bdrv_co_preadv_part(bs->backing, offset, bytes,
272
qiov, qiov_offset, 0);
273
274
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_task(BlockDriverState *bs, QCow2SubclusterType subc_type,
275
offset, bytes, qiov, qiov_offset);
276
}
277
278
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
279
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
280
return bdrv_co_preadv_part(s->data_file, host_offset,
281
bytes, qiov, qiov_offset, 0);
282
283
@@ -XXX,XX +XXX,XX @@ handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
284
return ret;
285
}
286
287
- BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
288
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
289
ret = bdrv_co_pwrite_zeroes(s->data_file, start_offset, nb_bytes,
290
BDRV_REQ_NO_FALLBACK);
291
if (ret < 0) {
292
@@ -XXX,XX +XXX,XX @@ int qcow2_co_pwritev_task(BlockDriverState *bs, uint64_t host_offset,
293
* guest data now.
294
*/
295
if (!merge_cow(offset, bytes, qiov, qiov_offset, l2meta)) {
296
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
297
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
298
trace_qcow2_writev_data(qemu_coroutine_self(), host_offset);
299
ret = bdrv_co_pwritev_part(s->data_file, host_offset,
300
bytes, qiov, qiov_offset, 0);
301
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
302
goto fail;
303
}
304
305
- BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
306
+ BLKDBG_CO_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
307
ret = bdrv_co_pwrite(s->data_file, cluster_offset, out_len, out_buf, 0);
308
if (ret < 0) {
309
goto fail;
310
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
311
312
out_buf = qemu_blockalign(bs, s->cluster_size);
313
314
- BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
315
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
316
ret = bdrv_co_pread(bs->file, coffset, csize, buf, 0);
317
if (ret < 0) {
318
goto fail;
319
@@ -XXX,XX +XXX,XX @@ qcow2_co_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
320
return offset;
321
}
322
323
- BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
324
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
325
return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0);
326
}
327
328
@@ -XXX,XX +XXX,XX @@ qcow2_co_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
329
return offset;
330
}
331
332
- BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
333
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
334
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
335
}
336
337
diff --git a/block/qed-table.c b/block/qed-table.c
338
index XXXXXXX..XXXXXXX 100644
339
--- a/block/qed-table.c
340
+++ b/block/qed-table.c
341
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s)
342
int coroutine_fn qed_write_l1_table(BDRVQEDState *s, unsigned int index,
343
unsigned int n)
166
{
344
{
167
BlockdevCreateOptions *create_options = NULL;
345
- BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
168
QDict *qdict;
346
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
169
- QObject *qobj;
347
return qed_write_table(s, s->header.l1_table_offset,
170
Visitor *v;
348
s->l1_table, index, n, false);
171
BlockDriverState *bs = NULL;
349
}
172
Error *local_err = NULL;
350
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request,
173
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
351
request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
174
qdict_put_str(qdict, "file", bs->node_name);
352
request->l2_table->table = qed_alloc_table(s);
175
353
176
/* Now get the QAPI type BlockdevCreateOptions */
354
- BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
177
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
355
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L2_LOAD);
178
- if (!qobj) {
356
ret = qed_read_table(s, offset, request->l2_table->table);
179
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
357
180
+ if (!v) {
358
if (ret) {
181
ret = -EINVAL;
359
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
182
goto finish;
360
unsigned int index, unsigned int n,
183
}
361
bool flush)
184
362
{
185
- v = qobject_input_visitor_new_keyval(qobj);
363
- BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
186
- qobject_unref(qobj);
364
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
187
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
365
return qed_write_table(s, request->l2_table->offset,
188
visit_free(v);
366
request->l2_table->table, index, n, flush);
189
367
}
190
diff --git a/block/qed.c b/block/qed.c
368
diff --git a/block/qed.c b/block/qed.c
191
index XXXXXXX..XXXXXXX 100644
369
index XXXXXXX..XXXXXXX 100644
192
--- a/block/qed.c
370
--- a/block/qed.c
193
+++ b/block/qed.c
371
+++ b/block/qed.c
194
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
372
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK
373
qed_read_backing_file(BDRVQEDState *s, uint64_t pos, QEMUIOVector *qiov)
195
{
374
{
196
BlockdevCreateOptions *create_options = NULL;
375
if (s->bs->backing) {
197
QDict *qdict;
376
- BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
198
- QObject *qobj;
377
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
199
Visitor *v;
378
return bdrv_co_preadv(s->bs->backing, pos, qiov->size, qiov, 0);
200
BlockDriverState *bs = NULL;
379
}
201
Error *local_err = NULL;
380
qemu_iovec_memset(qiov, 0, 0, qiov->size);
202
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
381
@@ -XXX,XX +XXX,XX @@ qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos, uint64_t len,
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;
382
goto out;
241
}
383
}
242
384
243
- v = qobject_input_visitor_new_keyval(crumpled);
385
- BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
244
visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err);
386
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_COW_WRITE);
245
visit_free(v);
387
ret = bdrv_co_pwritev(s->bs->file, offset, qiov.size, &qiov, 0);
246
- qobject_unref(crumpled);
388
if (ret < 0) {
247
389
goto out;
248
if (local_err) {
390
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK qed_aio_write_main(QEDAIOCB *acb)
249
error_propagate(errp, local_err);
391
250
diff --git a/block/sheepdog.c b/block/sheepdog.c
392
trace_qed_aio_write_main(s, acb, 0, offset, acb->cur_qiov.size);
251
index XXXXXXX..XXXXXXX 100644
393
252
--- a/block/sheepdog.c
394
- BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
253
+++ b/block/sheepdog.c
395
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
254
@@ -XXX,XX +XXX,XX @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
396
return bdrv_co_pwritev(s->bs->file, offset, acb->cur_qiov.size,
255
static SocketAddress *sd_server_config(QDict *options, Error **errp)
397
&acb->cur_qiov, 0);
398
}
399
@@ -XXX,XX +XXX,XX @@ qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
400
} else if (ret != QED_CLUSTER_FOUND) {
401
r = qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov);
402
} else {
403
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
404
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
405
r = bdrv_co_preadv(bs->file, offset, acb->cur_qiov.size,
406
&acb->cur_qiov, 0);
407
}
408
diff --git a/block/raw-format.c b/block/raw-format.c
409
index XXXXXXX..XXXXXXX 100644
410
--- a/block/raw-format.c
411
+++ b/block/raw-format.c
412
@@ -XXX,XX +XXX,XX @@ raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
413
return ret;
414
}
415
416
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
417
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
418
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
419
}
420
421
@@ -XXX,XX +XXX,XX @@ raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
422
goto fail;
423
}
424
425
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
426
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
427
ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
428
429
fail:
430
diff --git a/block/vmdk.c b/block/vmdk.c
431
index XXXXXXX..XXXXXXX 100644
432
--- a/block/vmdk.c
433
+++ b/block/vmdk.c
434
@@ -XXX,XX +XXX,XX @@ get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
435
if (skip_start_bytes > 0) {
436
if (copy_from_backing) {
437
/* qcow2 emits this on bs->file instead of bs->backing */
438
- BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
439
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_COW_READ);
440
ret = bdrv_co_pread(bs->backing, offset, skip_start_bytes,
441
whole_grain, 0);
442
if (ret < 0) {
443
@@ -XXX,XX +XXX,XX @@ get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
444
goto exit;
445
}
446
}
447
- BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
448
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_COW_WRITE);
449
ret = bdrv_co_pwrite(extent->file, cluster_offset, skip_start_bytes,
450
whole_grain, 0);
451
if (ret < 0) {
452
@@ -XXX,XX +XXX,XX @@ get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
453
if (skip_end_bytes < cluster_bytes) {
454
if (copy_from_backing) {
455
/* qcow2 emits this on bs->file instead of bs->backing */
456
- BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
457
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_COW_READ);
458
ret = bdrv_co_pread(bs->backing, offset + skip_end_bytes,
459
cluster_bytes - skip_end_bytes,
460
whole_grain + skip_end_bytes, 0);
461
@@ -XXX,XX +XXX,XX @@ get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
462
goto exit;
463
}
464
}
465
- BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
466
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_COW_WRITE);
467
ret = bdrv_co_pwrite(extent->file, cluster_offset + skip_end_bytes,
468
cluster_bytes - skip_end_bytes,
469
whole_grain + skip_end_bytes, 0);
470
@@ -XXX,XX +XXX,XX @@ vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, uint32_t offset)
256
{
471
{
257
QDict *server = NULL;
472
offset = cpu_to_le32(offset);
258
- QObject *crumpled_server = NULL;
473
/* update L2 table */
259
Visitor *iv = NULL;
474
- BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE);
260
SocketAddress *saddr = NULL;
475
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_L2_UPDATE);
261
Error *local_err = NULL;
476
if (bdrv_co_pwrite(extent->file,
262
477
((int64_t)m_data->l2_offset * 512)
263
qdict_extract_subqdict(options, &server, "server.");
478
+ (m_data->l2_index * sizeof(offset)),
264
479
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, VmdkExtent *extent,
265
- crumpled_server = qdict_crumple_for_keyval_qiv(server, errp);
480
}
266
- if (!crumpled_server) {
481
}
267
+ iv = qobject_input_visitor_new_flat_confused(server, errp);
482
l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes);
268
+ if (!iv) {
483
- BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
269
goto done;
484
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_L2_LOAD);
270
}
485
if (bdrv_co_pread(extent->file,
271
486
(int64_t)l2_offset * 512,
272
- iv = qobject_input_visitor_new_keyval(crumpled_server);
487
l2_size_bytes,
273
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
488
@@ -XXX,XX +XXX,XX @@ vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
274
if (local_err) {
489
n_bytes = buf_len + sizeof(VmdkGrainMarker);
275
error_propagate(errp, local_err);
490
qemu_iovec_init_buf(&local_qiov, data, n_bytes);
276
@@ -XXX,XX +XXX,XX @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
491
277
492
- BLKDBG_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED);
278
done:
493
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED);
279
visit_free(iv);
494
} else {
280
- qobject_unref(crumpled_server);
495
qemu_iovec_init(&local_qiov, qiov->niov);
281
qobject_unref(server);
496
qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes);
282
return saddr;
497
283
}
498
- BLKDBG_EVENT(extent->file, BLKDBG_WRITE_AIO);
284
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
499
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_WRITE_AIO);
285
{
500
}
286
BlockdevCreateOptions *create_options = NULL;
501
287
QDict *qdict, *location_qdict;
502
write_offset = cluster_offset + offset_in_cluster;
288
- QObject *crumpled;
503
@@ -XXX,XX +XXX,XX @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
289
Visitor *v;
504
290
char *redundancy;
505
291
Error *local_err = NULL;
506
if (!extent->compressed) {
292
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
507
- BLKDBG_EVENT(extent->file, BLKDBG_READ_AIO);
293
}
508
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_READ_AIO);
294
509
ret = bdrv_co_preadv(extent->file,
295
/* Get the QAPI object */
510
cluster_offset + offset_in_cluster, bytes,
296
- crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
511
qiov, 0);
297
- if (crumpled == NULL) {
512
@@ -XXX,XX +XXX,XX @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
298
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
513
buf_bytes = cluster_bytes * 2;
299
+ if (!v) {
514
cluster_buf = g_malloc(buf_bytes);
300
ret = -EINVAL;
515
uncomp_buf = g_malloc(cluster_bytes);
301
goto fail;
516
- BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED);
302
}
517
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_READ_COMPRESSED);
303
518
ret = bdrv_co_pread(extent->file, cluster_offset, buf_bytes, cluster_buf,
304
- v = qobject_input_visitor_new_keyval(crumpled);
519
0);
305
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
520
if (ret < 0) {
306
visit_free(v);
521
@@ -XXX,XX +XXX,XX @@ vmdk_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
307
- qobject_unref(crumpled);
522
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
308
523
309
if (local_err) {
524
/* qcow2 emits this on bs->file instead of bs->backing */
310
error_propagate(errp, local_err);
525
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
311
diff --git a/block/ssh.c b/block/ssh.c
526
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
312
index XXXXXXX..XXXXXXX 100644
527
ret = bdrv_co_preadv(bs->backing, offset, n_bytes,
313
--- a/block/ssh.c
528
&local_qiov, 0);
314
+++ b/block/ssh.c
529
if (ret < 0) {
315
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
530
@@ -XXX,XX +XXX,XX @@ vmdk_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix)
316
BlockdevOptionsSsh *result = NULL;
531
BDRVVmdkState *s = bs->opaque;
317
QemuOpts *opts = NULL;
532
VmdkExtent *extent = NULL;
318
Error *local_err = NULL;
533
int64_t sector_num = 0;
319
- QObject *crumpled;
534
- int64_t total_sectors = bdrv_nb_sectors(bs);
320
const QDictEntry *e;
535
+ int64_t total_sectors = bdrv_co_nb_sectors(bs);
321
Visitor *v;
536
int ret;
322
537
uint64_t cluster_offset;
323
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
538
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
--
539
--
450
2.13.6
540
2.41.0
451
452
diff view generated by jsdifflib