summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYogita Urade <yogita.urade@windriver.com>2024-08-21 09:01:03 +0000
committerSteve Sakoman <steve@sakoman.com>2024-09-03 05:39:12 -0700
commit8c533e92423a77efe3b5d1419ec69723d7e23146 (patch)
tree853bddcc5cfbaecfcbfb45a71eddcdca7f5758d6
parentc5627ab06fc07221237b9a7059ac378ea80578f8 (diff)
downloadpoky-8c533e92423a77efe3b5d1419ec69723d7e23146.tar.gz
qemu: fix CVE-2024-4467
A flaw was found in the QEMU disk image utility (qemu-img) 'info' command. A specially crafted image file containing a `json:{}` value describing block devices in QMP could cause the qemu-img process on the host to consume large amounts of memory or CPU time, leading to denial of service or read/write to an existing external file Reference: https://nvd.nist.gov/vuln/detail/CVE-2024-4467 Upstream Patches: https://gitlab.com/qemu-project/qemu/-/commit/bd385a5298d7062668e804d73944d52aec9549f1 https://gitlab.com/qemu-project/qemu/-/commit/2eb42a728d27a43fdcad5f37d3f65706ce6deba5 https://gitlab.com/qemu-project/qemu/-/commit/7e1110664ecbc4826f3c978ccb06b6c1bce823e6 https://gitlab.com/qemu-project/qemu/-/commit/6bc30f19498547fac9cef98316a65cf6c1f14205 https://gitlab.com/qemu-project/qemu/-/commit/7ead946998610657d38d1a505d5f25300d4ca613 (From OE-Core rev: 0e309919b8807950cebc8924fc1e15763548b1f1) Signed-off-by: Yogita Urade <yogita.urade@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-devtools/qemu/qemu.inc5
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0001.patch112
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0002.patch55
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0003.patch57
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0004.patch1187
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0005.patch239
6 files changed, 1655 insertions, 0 deletions
diff --git a/meta/recipes-devtools/qemu/qemu.inc b/meta/recipes-devtools/qemu/qemu.inc
index 3643b9a544..50d92b04bd 100644
--- a/meta/recipes-devtools/qemu/qemu.inc
+++ b/meta/recipes-devtools/qemu/qemu.inc
@@ -40,6 +40,11 @@ SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \
40 file://0005-tests-tcg-Check-that-shmat-does-not-break-proc-self-.patch \ 40 file://0005-tests-tcg-Check-that-shmat-does-not-break-proc-self-.patch \
41 file://qemu-guest-agent.init \ 41 file://qemu-guest-agent.init \
42 file://qemu-guest-agent.udev \ 42 file://qemu-guest-agent.udev \
43 file://CVE-2024-4467-0001.patch \
44 file://CVE-2024-4467-0002.patch \
45 file://CVE-2024-4467-0003.patch \
46 file://CVE-2024-4467-0004.patch \
47 file://CVE-2024-4467-0005.patch \
43 " 48 "
44UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar" 49UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar"
45 50
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0001.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0001.patch
new file mode 100644
index 0000000000..dbcc71bb4e
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0001.patch
@@ -0,0 +1,112 @@
1From bd385a5298d7062668e804d73944d52aec9549f1 Mon Sep 17 00:00:00 2001
2From: Kevin Wolf <kwolf@redhat.com>
3Date: Fri, 16 Aug 2024 08:29:04 +0000
4Subject: [PATCH] qcow2: Don't open data_file with BDRV_O_NO_IO
5
6One use case for 'qemu-img info' is verifying that untrusted images
7don't reference an unwanted external file, be it as a backing file or an
8external data file. To make sure that calling 'qemu-img info' can't
9already have undesired side effects with a malicious image, just don't
10open the data file at all with BDRV_O_NO_IO. If nothing ever tries to do
11I/O, we don't need to have it open.
12
13This changes the output of iotests case 061, which used 'qemu-img info'
14to show that opening an image with an invalid data file fails. After
15this patch, it succeeds. Replace this part of the test with a qemu-io
16call, but keep the final 'qemu-img info' to show that the invalid data
17file is correctly displayed in the output.
18
19Fixes: CVE-2024-4467
20Cc: qemu-stable@nongnu.org
21Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22Reviewed-by: Eric Blake <eblake@redhat.com>
23Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
24Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
25
26CVE: CVE-2024-4667
27Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/bd385a5298d7062668e804d73944d52aec9549f1]
28
29Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
30---
31 block/qcow2.c | 17 ++++++++++++++++-
32 tests/qemu-iotests/061 | 6 ++++--
33 tests/qemu-iotests/061.out | 8 ++++++--
34 3 files changed, 26 insertions(+), 5 deletions(-)
35
36diff --git a/block/qcow2.c b/block/qcow2.c
37index 13e032bd5..7af7c0bee 100644
38--- a/block/qcow2.c
39+++ b/block/qcow2.c
40@@ -1636,7 +1636,22 @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
41 goto fail;
42 }
43
44- if (open_data_file) {
45+ if (open_data_file && (flags & BDRV_O_NO_IO)) {
46+ /*
47+ * Don't open the data file for 'qemu-img info' so that it can be used
48+ * to verify that an untrusted qcow2 image doesn't refer to external
49+ * files.
50+ *
51+ * Note: This still makes has_data_file() return true.
52+ */
53+ if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
54+ s->data_file = NULL;
55+ } else {
56+ s->data_file = bs->file;
57+ }
58+ qdict_extract_subqdict(options, NULL, "data-file.");
59+ qdict_del(options, "data-file");
60+ } else if (open_data_file) {
61 /* Open external data file */
62 bdrv_graph_co_rdunlock();
63 s->data_file = bdrv_co_open_child(NULL, options, "data-file", bs,
64diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
65index 53c7d428e..b71ac097d 100755
66--- a/tests/qemu-iotests/061
67+++ b/tests/qemu-iotests/061
68@@ -326,12 +326,14 @@ $QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
69 echo
70 _make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
71 $QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
72-_img_info --format-specific
73+$QEMU_IO -c "read 0 4k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
74+$QEMU_IO -c "open -o data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" -c "read 0 4k" | _filter_qemu_io
75 TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
76
77 echo
78 $QEMU_IMG amend -o "data_file=" --image-opts "data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG"
79-_img_info --format-specific
80+$QEMU_IO -c "read 0 4k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
81+$QEMU_IO -c "open -o data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" -c "read 0 4k" | _filter_qemu_io
82 TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
83
84 echo
85diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
86index 139fc6817..24c33add7 100644
87--- a/tests/qemu-iotests/061.out
88+++ b/tests/qemu-iotests/061.out
89@@ -545,7 +545,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
90 qemu-img: data-file can only be set for images that use an external data file
91
92 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
93-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'foo': No such file or directory
94+qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'foo': No such file or directory
95+read 4096/4096 bytes at offset 0
96+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
97 image: TEST_DIR/t.IMGFMT
98 file format: IMGFMT
99 virtual size: 64 MiB (67108864 bytes)
100@@ -560,7 +562,9 @@ Format specific information:
101 corrupt: false
102 extended l2: false
103
104-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'data-file' is required for this image
105+qemu-io: can't open device TEST_DIR/t.IMGFMT: 'data-file' is required for this image
106+read 4096/4096 bytes at offset 0
107+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
108 image: TEST_DIR/t.IMGFMT
109 file format: IMGFMT
110 virtual size: 64 MiB (67108864 bytes)
111--
1122.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0002.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0002.patch
new file mode 100644
index 0000000000..686176189c
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0002.patch
@@ -0,0 +1,55 @@
1From 2eb42a728d27a43fdcad5f37d3f65706ce6deba5 Mon Sep 17 00:00:00 2001
2From: Kevin Wolf <kwolf@redhat.com>
3Date: Fri, 16 Aug 2024 09:35:24 +0000
4Subject: [PATCH] iotests/244: Don't store data-file with protocol in image
5
6We want to disable filename parsing for data files because it's too easy
7to abuse in malicious image files. Make the test ready for the change by
8passing the data file explicitly in command line options.
9
10Cc: qemu-stable@nongnu.org
11Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12Reviewed-by: Eric Blake <eblake@redhat.com>
13Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
15
16CVE: CVE-2024-4467
17Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/2eb42a728d27a43fdcad5f37d3f65706ce6deba5]
18
19Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
20---
21 tests/qemu-iotests/244 | 19 ++++++++++++++++---
22 1 file changed, 16 insertions(+), 3 deletions(-)
23
24diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
25index 3e61fa25b..bb9cc6512 100755
26--- a/tests/qemu-iotests/244
27+++ b/tests/qemu-iotests/244
28@@ -215,9 +215,22 @@ $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
29 $QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
30
31 # blkdebug doesn't support copy offloading, so this tests the error path
32-$QEMU_IMG amend -f $IMGFMT -o "data_file=blkdebug::$TEST_IMG.data" "$TEST_IMG"
33-$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
34-$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
35+test_img_with_blkdebug="json:{
36+ 'driver': 'qcow2',
37+ 'file': {
38+ 'driver': 'file',
39+ 'filename': '$TEST_IMG'
40+ },
41+ 'data-file': {
42+ 'driver': 'blkdebug',
43+ 'image': {
44+ 'driver': 'file',
45+ 'filename': '$TEST_IMG.data'
46+ }
47+ }
48+}"
49+$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$test_img_with_blkdebug"
50+$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$test_img_with_blkdebug"
51
52 echo
53 echo "=== Flushing should flush the data file ==="
54--
552.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0003.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0003.patch
new file mode 100644
index 0000000000..02611d6732
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0003.patch
@@ -0,0 +1,57 @@
1From 7e1110664ecbc4826f3c978ccb06b6c1bce823e6 Mon Sep 17 00:00:00 2001
2From: Kevin Wolf <kwolf@redhat.com>
3Date: Fri, 16 Aug 2024 10:24:58 +0000
4Subject: [PATCH] iotests/270: Don't store data-file with json: prefix in image
5
6We want to disable filename parsing for data files because it's too easy
7to abuse in malicious image files. Make the test ready for the change by
8passing the data file explicitly in command line options.
9
10Cc: qemu-stable@nongnu.org
11Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12Reviewed-by: Eric Blake <eblake@redhat.com>
13Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
15
16CVE: CVE-2024-4467
17Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/7e1110664ecbc4826f3c978ccb06b6c1bce823e6]
18
19Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
20---
21 tests/qemu-iotests/270 | 14 +++++++++++---
22 1 file changed, 11 insertions(+), 3 deletions(-)
23
24diff --git a/tests/qemu-iotests/270 b/tests/qemu-iotests/270
25index 74352342d..c37b674aa 100755
26--- a/tests/qemu-iotests/270
27+++ b/tests/qemu-iotests/270
28@@ -60,8 +60,16 @@ _make_test_img -o cluster_size=2M,data_file="$TEST_IMG.orig" \
29 # "write" 2G of data without using any space.
30 # (qemu-img create does not like it, though, because null-co does not
31 # support image creation.)
32-$QEMU_IMG amend -o data_file="json:{'driver':'null-co',,'size':'4294967296'}" \
33- "$TEST_IMG"
34+test_img_with_null_data="json:{
35+ 'driver': '$IMGFMT',
36+ 'file': {
37+ 'filename': '$TEST_IMG'
38+ },
39+ 'data-file': {
40+ 'driver': 'null-co',
41+ 'size':'4294967296'
42+ }
43+}"
44
45 # This gives us a range of:
46 # 2^31 - 512 + 768 - 1 = 2^31 + 255 > 2^31
47@@ -74,7 +82,7 @@ $QEMU_IMG amend -o data_file="json:{'driver':'null-co',,'size':'4294967296'}" \
48 # on L2 boundaries, we need large L2 tables; hence the cluster size of
49 # 2 MB. (Anything from 256 kB should work, though, because then one L2
50 # table covers 8 GB.)
51-$QEMU_IO -c "write 768 $((2 ** 31 - 512))" "$TEST_IMG" | _filter_qemu_io
52+$QEMU_IO -c "write 768 $((2 ** 31 - 512))" "$test_img_with_null_data" | _filter_qemu_io
53
54 _check_test_img
55
56--
572.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0004.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0004.patch
new file mode 100644
index 0000000000..7568a453c4
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0004.patch
@@ -0,0 +1,1187 @@
1From 6bc30f19498547fac9cef98316a65cf6c1f14205 Mon Sep 17 00:00:00 2001
2From: Stefan Hajnoczi <stefanha@redhat.com>
3Date: Tue, 5 Dec 2023 13:20:02 -0500
4Subject: [PATCH] graph-lock: remove AioContext locking
5
6Stop acquiring/releasing the AioContext lock in
7bdrv_graph_wrlock()/bdrv_graph_unlock() since the lock no longer has any
8effect.
9
10The distinction between bdrv_graph_wrunlock() and
11bdrv_graph_wrunlock_ctx() becomes meaningless and they can be collapsed
12into one function.
13
14Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15Reviewed-by: Eric Blake <eblake@redhat.com>
16Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17Message-ID: <20231205182011.1976568-6-stefanha@redhat.com>
18Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
20CVE: CVE-2024-4467
21Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/6bc30f19498547fac9cef98316a65cf6c1f14205]
22
23Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
24---
25 block.c | 50 +++++++++++++++---------------
26 block/backup.c | 4 +--
27 block/blklogwrites.c | 8 ++---
28 block/blkverify.c | 4 +--
29 block/block-backend.c | 11 +++----
30 block/commit.c | 16 +++++-----
31 block/graph-lock.c | 44 ++------------------------
32 block/mirror.c | 22 ++++++-------
33 block/qcow2.c | 4 +--
34 block/quorum.c | 8 ++---
35 block/replication.c | 14 ++++-----
36 block/snapshot.c | 4 +--
37 block/stream.c | 12 +++----
38 block/vmdk.c | 20 ++++++------
39 blockdev.c | 8 ++---
40 blockjob.c | 12 +++----
41 include/block/graph-lock.h | 21 ++-----------
42 scripts/block-coroutine-wrapper.py | 4 +--
43 tests/unit/test-bdrv-drain.c | 40 ++++++++++++------------
44 tests/unit/test-bdrv-graph-mod.c | 20 ++++++------
45 20 files changed, 133 insertions(+), 193 deletions(-)
46
47diff --git a/block.c b/block.c
48index bfb0861ec..25e1ebc60 100644
49--- a/block.c
50+++ b/block.c
51@@ -1708,12 +1708,12 @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
52 open_failed:
53 bs->drv = NULL;
54
55- bdrv_graph_wrlock(NULL);
56+ bdrv_graph_wrlock();
57 if (bs->file != NULL) {
58 bdrv_unref_child(bs, bs->file);
59 assert(!bs->file);
60 }
61- bdrv_graph_wrunlock(NULL);
62+ bdrv_graph_wrunlock();
63
64 g_free(bs->opaque);
65 bs->opaque = NULL;
66@@ -3575,9 +3575,9 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
67
68 bdrv_ref(drain_bs);
69 bdrv_drained_begin(drain_bs);
70- bdrv_graph_wrlock(backing_hd);
71+ bdrv_graph_wrlock();
72 ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
73- bdrv_graph_wrunlock(backing_hd);
74+ bdrv_graph_wrunlock();
75 bdrv_drained_end(drain_bs);
76 bdrv_unref(drain_bs);
77
78@@ -3790,13 +3790,13 @@ BdrvChild *bdrv_open_child(const char *filename,
79 return NULL;
80 }
81
82- bdrv_graph_wrlock(NULL);
83+ bdrv_graph_wrlock();
84 ctx = bdrv_get_aio_context(bs);
85 aio_context_acquire(ctx);
86 child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
87 errp);
88 aio_context_release(ctx);
89- bdrv_graph_wrunlock(NULL);
90+ bdrv_graph_wrunlock();
91
92 return child;
93 }
94@@ -4650,9 +4650,9 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
95 aio_context_release(ctx);
96 }
97
98- bdrv_graph_wrlock(NULL);
99+ bdrv_graph_wrlock();
100 tran_commit(tran);
101- bdrv_graph_wrunlock(NULL);
102+ bdrv_graph_wrunlock();
103
104 QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
105 BlockDriverState *bs = bs_entry->state.bs;
106@@ -4669,9 +4669,9 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
107 goto cleanup;
108
109 abort:
110- bdrv_graph_wrlock(NULL);
111+ bdrv_graph_wrlock();
112 tran_abort(tran);
113- bdrv_graph_wrunlock(NULL);
114+ bdrv_graph_wrunlock();
115
116 QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
117 if (bs_entry->prepared) {
118@@ -4852,12 +4852,12 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
119 }
120
121 bdrv_graph_rdunlock_main_loop();
122- bdrv_graph_wrlock(new_child_bs);
123+ bdrv_graph_wrlock();
124
125 ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
126 tran, errp);
127
128- bdrv_graph_wrunlock_ctx(ctx);
129+ bdrv_graph_wrunlock();
130
131 if (old_ctx != ctx) {
132 aio_context_release(ctx);
133@@ -5209,14 +5209,14 @@ static void bdrv_close(BlockDriverState *bs)
134 bs->drv = NULL;
135 }
136
137- bdrv_graph_wrlock(bs);
138+ bdrv_graph_wrlock();
139 QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
140 bdrv_unref_child(bs, child);
141 }
142
143 assert(!bs->backing);
144 assert(!bs->file);
145- bdrv_graph_wrunlock(bs);
146+ bdrv_graph_wrunlock();
147
148 g_free(bs->opaque);
149 bs->opaque = NULL;
150@@ -5509,9 +5509,9 @@ int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
151 bdrv_graph_rdunlock_main_loop();
152
153 bdrv_drained_begin(child_bs);
154- bdrv_graph_wrlock(bs);
155+ bdrv_graph_wrlock();
156 ret = bdrv_replace_node_common(bs, child_bs, true, true, errp);
157- bdrv_graph_wrunlock(bs);
158+ bdrv_graph_wrunlock();
159 bdrv_drained_end(child_bs);
160
161 return ret;
162@@ -5561,7 +5561,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
163 aio_context_acquire(old_context);
164 new_context = NULL;
165
166- bdrv_graph_wrlock(bs_top);
167+ bdrv_graph_wrlock();
168
169 child = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
170 &child_of_bds, bdrv_backing_role(bs_new),
171@@ -5593,7 +5593,7 @@ out:
172 tran_finalize(tran, ret);
173
174 bdrv_refresh_limits(bs_top, NULL, NULL);
175- bdrv_graph_wrunlock(bs_top);
176+ bdrv_graph_wrunlock();
177
178 bdrv_drained_end(bs_top);
179 bdrv_drained_end(bs_new);
180@@ -5620,7 +5620,7 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
181 bdrv_ref(old_bs);
182 bdrv_drained_begin(old_bs);
183 bdrv_drained_begin(new_bs);
184- bdrv_graph_wrlock(new_bs);
185+ bdrv_graph_wrlock();
186
187 bdrv_replace_child_tran(child, new_bs, tran);
188
189@@ -5631,7 +5631,7 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
190
191 tran_finalize(tran, ret);
192
193- bdrv_graph_wrunlock(new_bs);
194+ bdrv_graph_wrunlock();
195 bdrv_drained_end(old_bs);
196 bdrv_drained_end(new_bs);
197 bdrv_unref(old_bs);
198@@ -5718,9 +5718,9 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
199 bdrv_ref(bs);
200 bdrv_drained_begin(bs);
201 bdrv_drained_begin(new_node_bs);
202- bdrv_graph_wrlock(new_node_bs);
203+ bdrv_graph_wrlock();
204 ret = bdrv_replace_node(bs, new_node_bs, errp);
205- bdrv_graph_wrunlock(new_node_bs);
206+ bdrv_graph_wrunlock();
207 bdrv_drained_end(new_node_bs);
208 bdrv_drained_end(bs);
209 bdrv_unref(bs);
210@@ -5975,7 +5975,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
211
212 bdrv_ref(top);
213 bdrv_drained_begin(base);
214- bdrv_graph_wrlock(base);
215+ bdrv_graph_wrlock();
216
217 if (!top->drv || !base->drv) {
218 goto exit_wrlock;
219@@ -6015,7 +6015,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
220 * That's a FIXME.
221 */
222 bdrv_replace_node_common(top, base, false, false, &local_err);
223- bdrv_graph_wrunlock(base);
224+ bdrv_graph_wrunlock();
225
226 if (local_err) {
227 error_report_err(local_err);
228@@ -6052,7 +6052,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
229 goto exit;
230
231 exit_wrlock:
232- bdrv_graph_wrunlock(base);
233+ bdrv_graph_wrunlock();
234 exit:
235 bdrv_drained_end(base);
236 bdrv_unref(top);
237diff --git a/block/backup.c b/block/backup.c
238index 8aae5836d..ec29d6b81 100644
239--- a/block/backup.c
240+++ b/block/backup.c
241@@ -496,10 +496,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
242 block_copy_set_speed(bcs, speed);
243
244 /* Required permissions are taken by copy-before-write filter target */
245- bdrv_graph_wrlock(target);
246+ bdrv_graph_wrlock();
247 block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
248 &error_abort);
249- bdrv_graph_wrunlock(target);
250+ bdrv_graph_wrunlock();
251
252 return &job->common;
253
254diff --git a/block/blklogwrites.c b/block/blklogwrites.c
255index 84e03f309..ba717dab4 100644
256--- a/block/blklogwrites.c
257+++ b/block/blklogwrites.c
258@@ -251,9 +251,9 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
259 ret = 0;
260 fail_log:
261 if (ret < 0) {
262- bdrv_graph_wrlock(NULL);
263+ bdrv_graph_wrlock();
264 bdrv_unref_child(bs, s->log_file);
265- bdrv_graph_wrunlock(NULL);
266+ bdrv_graph_wrunlock();
267 s->log_file = NULL;
268 }
269 fail:
270@@ -265,10 +265,10 @@ static void blk_log_writes_close(BlockDriverState *bs)
271 {
272 BDRVBlkLogWritesState *s = bs->opaque;
273
274- bdrv_graph_wrlock(NULL);
275+ bdrv_graph_wrlock();
276 bdrv_unref_child(bs, s->log_file);
277 s->log_file = NULL;
278- bdrv_graph_wrunlock(NULL);
279+ bdrv_graph_wrunlock();
280 }
281
282 static int64_t coroutine_fn GRAPH_RDLOCK
283diff --git a/block/blkverify.c b/block/blkverify.c
284index 9b17c4664..ec45d8335 100644
285--- a/block/blkverify.c
286+++ b/block/blkverify.c
287@@ -151,10 +151,10 @@ static void blkverify_close(BlockDriverState *bs)
288 {
289 BDRVBlkverifyState *s = bs->opaque;
290
291- bdrv_graph_wrlock(NULL);
292+ bdrv_graph_wrlock();
293 bdrv_unref_child(bs, s->test_file);
294 s->test_file = NULL;
295- bdrv_graph_wrunlock(NULL);
296+ bdrv_graph_wrunlock();
297 }
298
299 static int64_t coroutine_fn GRAPH_RDLOCK
300diff --git a/block/block-backend.c b/block/block-backend.c
301index 86315d62c..a2348b31e 100644
302--- a/block/block-backend.c
303+++ b/block/block-backend.c
304@@ -885,7 +885,6 @@ void blk_remove_bs(BlockBackend *blk)
305 {
306 ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
307 BdrvChild *root;
308- AioContext *ctx;
309
310 GLOBAL_STATE_CODE();
311
312@@ -915,10 +914,9 @@ void blk_remove_bs(BlockBackend *blk)
313 root = blk->root;
314 blk->root = NULL;
315
316- ctx = bdrv_get_aio_context(root->bs);
317- bdrv_graph_wrlock(root->bs);
318+ bdrv_graph_wrlock();
319 bdrv_root_unref_child(root);
320- bdrv_graph_wrunlock_ctx(ctx);
321+ bdrv_graph_wrunlock();
322 }
323
324 /*
325@@ -929,16 +927,15 @@ void blk_remove_bs(BlockBackend *blk)
326 int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
327 {
328 ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
329- AioContext *ctx = bdrv_get_aio_context(bs);
330
331 GLOBAL_STATE_CODE();
332 bdrv_ref(bs);
333- bdrv_graph_wrlock(bs);
334+ bdrv_graph_wrlock();
335 blk->root = bdrv_root_attach_child(bs, "root", &child_root,
336 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
337 blk->perm, blk->shared_perm,
338 blk, errp);
339- bdrv_graph_wrunlock_ctx(ctx);
340+ bdrv_graph_wrunlock();
341 if (blk->root == NULL) {
342 return -EPERM;
343 }
344diff --git a/block/commit.c b/block/commit.c
345index 69cc75be0..1dd7a65ff 100644
346--- a/block/commit.c
347+++ b/block/commit.c
348@@ -100,9 +100,9 @@ static void commit_abort(Job *job)
349 bdrv_graph_rdunlock_main_loop();
350
351 bdrv_drained_begin(commit_top_backing_bs);
352- bdrv_graph_wrlock(commit_top_backing_bs);
353+ bdrv_graph_wrlock();
354 bdrv_replace_node(s->commit_top_bs, commit_top_backing_bs, &error_abort);
355- bdrv_graph_wrunlock(commit_top_backing_bs);
356+ bdrv_graph_wrunlock();
357 bdrv_drained_end(commit_top_backing_bs);
358
359 bdrv_unref(s->commit_top_bs);
360@@ -339,7 +339,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
361 * this is the responsibility of the interface (i.e. whoever calls
362 * commit_start()).
363 */
364- bdrv_graph_wrlock(top);
365+ bdrv_graph_wrlock();
366 s->base_overlay = bdrv_find_overlay(top, base);
367 assert(s->base_overlay);
368
369@@ -370,19 +370,19 @@ void commit_start(const char *job_id, BlockDriverState *bs,
370 ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
371 iter_shared_perms, errp);
372 if (ret < 0) {
373- bdrv_graph_wrunlock(top);
374+ bdrv_graph_wrunlock();
375 goto fail;
376 }
377 }
378
379 if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
380- bdrv_graph_wrunlock(top);
381+ bdrv_graph_wrunlock();
382 goto fail;
383 }
384 s->chain_frozen = true;
385
386 ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
387- bdrv_graph_wrunlock(top);
388+ bdrv_graph_wrunlock();
389
390 if (ret < 0) {
391 goto fail;
392@@ -434,9 +434,9 @@ fail:
393 * otherwise this would fail because of lack of permissions. */
394 if (commit_top_bs) {
395 bdrv_drained_begin(top);
396- bdrv_graph_wrlock(top);
397+ bdrv_graph_wrlock();
398 bdrv_replace_node(commit_top_bs, top, &error_abort);
399- bdrv_graph_wrunlock(top);
400+ bdrv_graph_wrunlock();
401 bdrv_drained_end(top);
402 }
403 }
404diff --git a/block/graph-lock.c b/block/graph-lock.c
405index 079e878d9..c81162b14 100644
406--- a/block/graph-lock.c
407+++ b/block/graph-lock.c
408@@ -106,27 +106,12 @@ static uint32_t reader_count(void)
409 return rd;
410 }
411
412-void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
413+void no_coroutine_fn bdrv_graph_wrlock(void)
414 {
415- AioContext *ctx = NULL;
416-
417 GLOBAL_STATE_CODE();
418 assert(!qatomic_read(&has_writer));
419 assert(!qemu_in_coroutine());
420
421- /*
422- * Release only non-mainloop AioContext. The mainloop often relies on the
423- * BQL and doesn't lock the main AioContext before doing things.
424- */
425- if (bs) {
426- ctx = bdrv_get_aio_context(bs);
427- if (ctx != qemu_get_aio_context()) {
428- aio_context_release(ctx);
429- } else {
430- ctx = NULL;
431- }
432- }
433-
434 /* Make sure that constantly arriving new I/O doesn't cause starvation */
435 bdrv_drain_all_begin_nopoll();
436
437@@ -155,27 +140,13 @@ void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
438 } while (reader_count() >= 1);
439
440 bdrv_drain_all_end();
441-
442- if (ctx) {
443- aio_context_acquire(bdrv_get_aio_context(bs));
444- }
445 }
446
447-void no_coroutine_fn bdrv_graph_wrunlock_ctx(AioContext *ctx)
448+void no_coroutine_fn bdrv_graph_wrunlock(void)
449 {
450 GLOBAL_STATE_CODE();
451 assert(qatomic_read(&has_writer));
452
453- /*
454- * Release only non-mainloop AioContext. The mainloop often relies on the
455- * BQL and doesn't lock the main AioContext before doing things.
456- */
457- if (ctx && ctx != qemu_get_aio_context()) {
458- aio_context_release(ctx);
459- } else {
460- ctx = NULL;
461- }
462-
463 WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
464 /*
465 * No need for memory barriers, this works in pair with
466@@ -197,17 +168,6 @@ void no_coroutine_fn bdrv_graph_wrunlock_ctx(AioContext *ctx)
467 * progress.
468 */
469 aio_bh_poll(qemu_get_aio_context());
470-
471- if (ctx) {
472- aio_context_acquire(ctx);
473- }
474-}
475-
476-void no_coroutine_fn bdrv_graph_wrunlock(BlockDriverState *bs)
477-{
478- AioContext *ctx = bs ? bdrv_get_aio_context(bs) : NULL;
479-
480- bdrv_graph_wrunlock_ctx(ctx);
481 }
482
483 void coroutine_fn bdrv_graph_co_rdlock(void)
484diff --git a/block/mirror.c b/block/mirror.c
485index abbddb39e..f9db6f0f7 100644
486--- a/block/mirror.c
487+++ b/block/mirror.c
488@@ -768,7 +768,7 @@ static int mirror_exit_common(Job *job)
489 * check for an op blocker on @to_replace, and we have our own
490 * there.
491 */
492- bdrv_graph_wrlock(target_bs);
493+ bdrv_graph_wrlock();
494 if (bdrv_recurse_can_replace(src, to_replace)) {
495 bdrv_replace_node(to_replace, target_bs, &local_err);
496 } else {
497@@ -777,7 +777,7 @@ static int mirror_exit_common(Job *job)
498 "would not lead to an abrupt change of visible data",
499 to_replace->node_name, target_bs->node_name);
500 }
501- bdrv_graph_wrunlock(target_bs);
502+ bdrv_graph_wrunlock();
503 bdrv_drained_end(to_replace);
504 if (local_err) {
505 error_report_err(local_err);
506@@ -800,9 +800,9 @@ static int mirror_exit_common(Job *job)
507 * valid.
508 */
509 block_job_remove_all_bdrv(bjob);
510- bdrv_graph_wrlock(mirror_top_bs);
511+ bdrv_graph_wrlock();
512 bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
513- bdrv_graph_wrunlock(mirror_top_bs);
514+ bdrv_graph_wrunlock();
515
516 bdrv_drained_end(target_bs);
517 bdrv_unref(target_bs);
518@@ -1916,13 +1916,13 @@ static BlockJob *mirror_start_job(
519 */
520 bdrv_disable_dirty_bitmap(s->dirty_bitmap);
521
522- bdrv_graph_wrlock(bs);
523+ bdrv_graph_wrlock();
524 ret = block_job_add_bdrv(&s->common, "source", bs, 0,
525 BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
526 BLK_PERM_CONSISTENT_READ,
527 errp);
528 if (ret < 0) {
529- bdrv_graph_wrunlock(bs);
530+ bdrv_graph_wrunlock();
531 goto fail;
532 }
533
534@@ -1967,17 +1967,17 @@ static BlockJob *mirror_start_job(
535 ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
536 iter_shared_perms, errp);
537 if (ret < 0) {
538- bdrv_graph_wrunlock(bs);
539+ bdrv_graph_wrunlock();
540 goto fail;
541 }
542 }
543
544 if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
545- bdrv_graph_wrunlock(bs);
546+ bdrv_graph_wrunlock();
547 goto fail;
548 }
549 }
550- bdrv_graph_wrunlock(bs);
551+ bdrv_graph_wrunlock();
552
553 QTAILQ_INIT(&s->ops_in_flight);
554
555@@ -2003,12 +2003,12 @@ fail:
556
557 bs_opaque->stop = true;
558 bdrv_drained_begin(bs);
559- bdrv_graph_wrlock(bs);
560+ bdrv_graph_wrlock();
561 assert(mirror_top_bs->backing->bs == bs);
562 bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
563 &error_abort);
564 bdrv_replace_node(mirror_top_bs, bs, &error_abort);
565- bdrv_graph_wrunlock(bs);
566+ bdrv_graph_wrunlock();
567 bdrv_drained_end(bs);
568
569 bdrv_unref(mirror_top_bs);
570diff --git a/block/qcow2.c b/block/qcow2.c
571index 7af7c0bee..77dd49d4f 100644
572--- a/block/qcow2.c
573+++ b/block/qcow2.c
574@@ -2822,9 +2822,9 @@ qcow2_do_close(BlockDriverState *bs, bool close_data_file)
575 if (close_data_file && has_data_file(bs)) {
576 GLOBAL_STATE_CODE();
577 bdrv_graph_rdunlock_main_loop();
578- bdrv_graph_wrlock(NULL);
579+ bdrv_graph_wrlock();
580 bdrv_unref_child(bs, s->data_file);
581- bdrv_graph_wrunlock(NULL);
582+ bdrv_graph_wrunlock();
583 s->data_file = NULL;
584 bdrv_graph_rdlock_main_loop();
585 }
586diff --git a/block/quorum.c b/block/quorum.c
587index 505b8b3e1..db8fe891c 100644
588--- a/block/quorum.c
589+++ b/block/quorum.c
590@@ -1037,14 +1037,14 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
591
592 close_exit:
593 /* cleanup on error */
594- bdrv_graph_wrlock(NULL);
595+ bdrv_graph_wrlock();
596 for (i = 0; i < s->num_children; i++) {
597 if (!opened[i]) {
598 continue;
599 }
600 bdrv_unref_child(bs, s->children[i]);
601 }
602- bdrv_graph_wrunlock(NULL);
603+ bdrv_graph_wrunlock();
604 g_free(s->children);
605 g_free(opened);
606 exit:
607@@ -1057,11 +1057,11 @@ static void quorum_close(BlockDriverState *bs)
608 BDRVQuorumState *s = bs->opaque;
609 int i;
610
611- bdrv_graph_wrlock(NULL);
612+ bdrv_graph_wrlock();
613 for (i = 0; i < s->num_children; i++) {
614 bdrv_unref_child(bs, s->children[i]);
615 }
616- bdrv_graph_wrunlock(NULL);
617+ bdrv_graph_wrunlock();
618
619 g_free(s->children);
620 }
621diff --git a/block/replication.c b/block/replication.c
622index 5ded5f1ca..424b537ff 100644
623--- a/block/replication.c
624+++ b/block/replication.c
625@@ -560,7 +560,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
626 return;
627 }
628
629- bdrv_graph_wrlock(bs);
630+ bdrv_graph_wrlock();
631
632 bdrv_ref(hidden_disk->bs);
633 s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk",
634@@ -568,7 +568,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
635 &local_err);
636 if (local_err) {
637 error_propagate(errp, local_err);
638- bdrv_graph_wrunlock(bs);
639+ bdrv_graph_wrunlock();
640 aio_context_release(aio_context);
641 return;
642 }
643@@ -579,7 +579,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
644 BDRV_CHILD_DATA, &local_err);
645 if (local_err) {
646 error_propagate(errp, local_err);
647- bdrv_graph_wrunlock(bs);
648+ bdrv_graph_wrunlock();
649 aio_context_release(aio_context);
650 return;
651 }
652@@ -592,7 +592,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
653 if (!top_bs || !bdrv_is_root_node(top_bs) ||
654 !check_top_bs(top_bs, bs)) {
655 error_setg(errp, "No top_bs or it is invalid");
656- bdrv_graph_wrunlock(bs);
657+ bdrv_graph_wrunlock();
658 reopen_backing_file(bs, false, NULL);
659 aio_context_release(aio_context);
660 return;
661@@ -600,7 +600,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
662 bdrv_op_block_all(top_bs, s->blocker);
663 bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
664
665- bdrv_graph_wrunlock(bs);
666+ bdrv_graph_wrunlock();
667
668 s->backup_job = backup_job_create(
669 NULL, s->secondary_disk->bs, s->hidden_disk->bs,
670@@ -691,12 +691,12 @@ static void replication_done(void *opaque, int ret)
671 if (ret == 0) {
672 s->stage = BLOCK_REPLICATION_DONE;
673
674- bdrv_graph_wrlock(NULL);
675+ bdrv_graph_wrlock();
676 bdrv_unref_child(bs, s->secondary_disk);
677 s->secondary_disk = NULL;
678 bdrv_unref_child(bs, s->hidden_disk);
679 s->hidden_disk = NULL;
680- bdrv_graph_wrunlock(NULL);
681+ bdrv_graph_wrunlock();
682
683 s->error = 0;
684 } else {
685diff --git a/block/snapshot.c b/block/snapshot.c
686index c4d40e80d..6fd720aef 100644
687--- a/block/snapshot.c
688+++ b/block/snapshot.c
689@@ -292,9 +292,9 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
690 }
691
692 /* .bdrv_open() will re-attach it */
693- bdrv_graph_wrlock(NULL);
694+ bdrv_graph_wrlock();
695 bdrv_unref_child(bs, fallback);
696- bdrv_graph_wrunlock(NULL);
697+ bdrv_graph_wrunlock();
698
699 ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
700 open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
701diff --git a/block/stream.c b/block/stream.c
702index 01fe7c0f1..048c2d282 100644
703--- a/block/stream.c
704+++ b/block/stream.c
705@@ -99,9 +99,9 @@ static int stream_prepare(Job *job)
706 }
707 }
708
709- bdrv_graph_wrlock(s->target_bs);
710+ bdrv_graph_wrlock();
711 bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
712- bdrv_graph_wrunlock(s->target_bs);
713+ bdrv_graph_wrunlock();
714
715 /*
716 * This call will do I/O, so the graph can change again from here on.
717@@ -366,10 +366,10 @@ void stream_start(const char *job_id, BlockDriverState *bs,
718 * already have our own plans. Also don't allow resize as the image size is
719 * queried only at the job start and then cached.
720 */
721- bdrv_graph_wrlock(bs);
722+ bdrv_graph_wrlock();
723 if (block_job_add_bdrv(&s->common, "active node", bs, 0,
724 basic_flags | BLK_PERM_WRITE, errp)) {
725- bdrv_graph_wrunlock(bs);
726+ bdrv_graph_wrunlock();
727 goto fail;
728 }
729
730@@ -389,11 +389,11 @@ void stream_start(const char *job_id, BlockDriverState *bs,
731 ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
732 basic_flags, errp);
733 if (ret < 0) {
734- bdrv_graph_wrunlock(bs);
735+ bdrv_graph_wrunlock();
736 goto fail;
737 }
738 }
739- bdrv_graph_wrunlock(bs);
740+ bdrv_graph_wrunlock();
741
742 s->base_overlay = base_overlay;
743 s->above_base = above_base;
744diff --git a/block/vmdk.c b/block/vmdk.c
745index d6971c706..bf78e1238 100644
746--- a/block/vmdk.c
747+++ b/block/vmdk.c
748@@ -272,7 +272,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
749 BDRVVmdkState *s = bs->opaque;
750 VmdkExtent *e;
751
752- bdrv_graph_wrlock(NULL);
753+ bdrv_graph_wrlock();
754 for (i = 0; i < s->num_extents; i++) {
755 e = &s->extents[i];
756 g_free(e->l1_table);
757@@ -283,7 +283,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
758 bdrv_unref_child(bs, e->file);
759 }
760 }
761- bdrv_graph_wrunlock(NULL);
762+ bdrv_graph_wrunlock();
763
764 g_free(s->extents);
765 }
766@@ -1247,9 +1247,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
767 0, 0, 0, 0, 0, &extent, errp);
768 if (ret < 0) {
769 bdrv_graph_rdunlock_main_loop();
770- bdrv_graph_wrlock(NULL);
771+ bdrv_graph_wrlock();
772 bdrv_unref_child(bs, extent_file);
773- bdrv_graph_wrunlock(NULL);
774+ bdrv_graph_wrunlock();
775 bdrv_graph_rdlock_main_loop();
776 goto out;
777 }
778@@ -1266,9 +1266,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
779 g_free(buf);
780 if (ret) {
781 bdrv_graph_rdunlock_main_loop();
782- bdrv_graph_wrlock(NULL);
783+ bdrv_graph_wrlock();
784 bdrv_unref_child(bs, extent_file);
785- bdrv_graph_wrunlock(NULL);
786+ bdrv_graph_wrunlock();
787 bdrv_graph_rdlock_main_loop();
788 goto out;
789 }
790@@ -1277,9 +1277,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
791 ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
792 if (ret) {
793 bdrv_graph_rdunlock_main_loop();
794- bdrv_graph_wrlock(NULL);
795+ bdrv_graph_wrlock();
796 bdrv_unref_child(bs, extent_file);
797- bdrv_graph_wrunlock(NULL);
798+ bdrv_graph_wrunlock();
799 bdrv_graph_rdlock_main_loop();
800 goto out;
801 }
802@@ -1287,9 +1287,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
803 } else {
804 error_setg(errp, "Unsupported extent type '%s'", type);
805 bdrv_graph_rdunlock_main_loop();
806- bdrv_graph_wrlock(NULL);
807+ bdrv_graph_wrlock();
808 bdrv_unref_child(bs, extent_file);
809- bdrv_graph_wrunlock(NULL);
810+ bdrv_graph_wrunlock();
811 bdrv_graph_rdlock_main_loop();
812 ret = -ENOTSUP;
813 goto out;
814diff --git a/blockdev.c b/blockdev.c
815index c91f49e7b..9e1381169 100644
816--- a/blockdev.c
817+++ b/blockdev.c
818@@ -1611,9 +1611,9 @@ static void external_snapshot_abort(void *opaque)
819 }
820
821 bdrv_drained_begin(state->new_bs);
822- bdrv_graph_wrlock(state->old_bs);
823+ bdrv_graph_wrlock();
824 bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
825- bdrv_graph_wrunlock(state->old_bs);
826+ bdrv_graph_wrunlock();
827 bdrv_drained_end(state->new_bs);
828
829 bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
830@@ -3657,7 +3657,7 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
831 BlockDriverState *parent_bs, *new_bs = NULL;
832 BdrvChild *p_child;
833
834- bdrv_graph_wrlock(NULL);
835+ bdrv_graph_wrlock();
836
837 parent_bs = bdrv_lookup_bs(parent, parent, errp);
838 if (!parent_bs) {
839@@ -3693,7 +3693,7 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
840 }
841
842 out:
843- bdrv_graph_wrunlock(NULL);
844+ bdrv_graph_wrunlock();
845 }
846
847 BlockJobInfoList *qmp_query_block_jobs(Error **errp)
848diff --git a/blockjob.c b/blockjob.c
849index b7a29052b..731041231 100644
850--- a/blockjob.c
851+++ b/blockjob.c
852@@ -199,7 +199,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
853 * to process an already freed BdrvChild.
854 */
855 aio_context_release(job->job.aio_context);
856- bdrv_graph_wrlock(NULL);
857+ bdrv_graph_wrlock();
858 aio_context_acquire(job->job.aio_context);
859 while (job->nodes) {
860 GSList *l = job->nodes;
861@@ -212,7 +212,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
862
863 g_slist_free_1(l);
864 }
865- bdrv_graph_wrunlock_ctx(job->job.aio_context);
866+ bdrv_graph_wrunlock();
867 }
868
869 bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
870@@ -514,7 +514,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
871 int ret;
872 GLOBAL_STATE_CODE();
873
874- bdrv_graph_wrlock(bs);
875+ bdrv_graph_wrlock();
876
877 if (job_id == NULL && !(flags & JOB_INTERNAL)) {
878 job_id = bdrv_get_device_name(bs);
879@@ -523,7 +523,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
880 job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
881 flags, cb, opaque, errp);
882 if (job == NULL) {
883- bdrv_graph_wrunlock(bs);
884+ bdrv_graph_wrunlock();
885 return NULL;
886 }
887
888@@ -563,11 +563,11 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
889 goto fail;
890 }
891
892- bdrv_graph_wrunlock(bs);
893+ bdrv_graph_wrunlock();
894 return job;
895
896 fail:
897- bdrv_graph_wrunlock(bs);
898+ bdrv_graph_wrunlock();
899 job_early_fail(&job->job);
900 return NULL;
901 }
902diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
903index 22b5db1ed..d7545e82d 100644
904--- a/include/block/graph-lock.h
905+++ b/include/block/graph-lock.h
906@@ -110,34 +110,17 @@ void unregister_aiocontext(AioContext *ctx);
907 *
908 * The wrlock can only be taken from the main loop, with BQL held, as only the
909 * main loop is allowed to modify the graph.
910- *
911- * If @bs is non-NULL, its AioContext is temporarily released.
912- *
913- * This function polls. Callers must not hold the lock of any AioContext other
914- * than the current one and the one of @bs.
915 */
916 void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA
917-bdrv_graph_wrlock(BlockDriverState *bs);
918+bdrv_graph_wrlock(void);
919
920 /*
921 * bdrv_graph_wrunlock:
922 * Write finished, reset global has_writer to 0 and restart
923 * all readers that are waiting.
924- *
925- * If @bs is non-NULL, its AioContext is temporarily released.
926- */
927-void no_coroutine_fn TSA_RELEASE(graph_lock) TSA_NO_TSA
928-bdrv_graph_wrunlock(BlockDriverState *bs);
929-
930-/*
931- * bdrv_graph_wrunlock_ctx:
932- * Write finished, reset global has_writer to 0 and restart
933- * all readers that are waiting.
934- *
935- * If @ctx is non-NULL, its lock is temporarily released.
936 */
937 void no_coroutine_fn TSA_RELEASE(graph_lock) TSA_NO_TSA
938-bdrv_graph_wrunlock_ctx(AioContext *ctx);
939+bdrv_graph_wrunlock(void);
940
941 /*
942 * bdrv_graph_co_rdlock:
943diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
944index a38e5833f..38364fa55 100644
945--- a/scripts/block-coroutine-wrapper.py
946+++ b/scripts/block-coroutine-wrapper.py
947@@ -261,8 +261,8 @@ def gen_no_co_wrapper(func: FuncDecl) -> str:
948 graph_lock=' bdrv_graph_rdlock_main_loop();'
949 graph_unlock=' bdrv_graph_rdunlock_main_loop();'
950 elif func.graph_wrlock:
951- graph_lock=' bdrv_graph_wrlock(NULL);'
952- graph_unlock=' bdrv_graph_wrunlock(NULL);'
953+ graph_lock=' bdrv_graph_wrlock();'
954+ graph_unlock=' bdrv_graph_wrunlock();'
955
956 return f"""\
957 /*
958diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
959index 704d1a3f3..d9754dfeb 100644
960--- a/tests/unit/test-bdrv-drain.c
961+++ b/tests/unit/test-bdrv-drain.c
962@@ -807,9 +807,9 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
963 tjob->bs = src;
964 job = &tjob->common;
965
966- bdrv_graph_wrlock(target);
967+ bdrv_graph_wrlock();
968 block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
969- bdrv_graph_wrunlock(target);
970+ bdrv_graph_wrunlock();
971
972 switch (result) {
973 case TEST_JOB_SUCCESS:
974@@ -991,11 +991,11 @@ static void bdrv_test_top_close(BlockDriverState *bs)
975 {
976 BdrvChild *c, *next_c;
977
978- bdrv_graph_wrlock(NULL);
979+ bdrv_graph_wrlock();
980 QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
981 bdrv_unref_child(bs, c);
982 }
983- bdrv_graph_wrunlock(NULL);
984+ bdrv_graph_wrunlock();
985 }
986
987 static int coroutine_fn GRAPH_RDLOCK
988@@ -1085,10 +1085,10 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
989
990 null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
991 &error_abort);
992- bdrv_graph_wrlock(NULL);
993+ bdrv_graph_wrlock();
994 bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds,
995 BDRV_CHILD_DATA, &error_abort);
996- bdrv_graph_wrunlock(NULL);
997+ bdrv_graph_wrunlock();
998
999 /* This child will be the one to pass to requests through to, and
1000 * it will stall until a drain occurs */
1001@@ -1096,21 +1096,21 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
1002 &error_abort);
1003 child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS;
1004 /* Takes our reference to child_bs */
1005- bdrv_graph_wrlock(NULL);
1006+ bdrv_graph_wrlock();
1007 tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child",
1008 &child_of_bds,
1009 BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
1010 &error_abort);
1011- bdrv_graph_wrunlock(NULL);
1012+ bdrv_graph_wrunlock();
1013
1014 /* This child is just there to be deleted
1015 * (for detach_instead_of_delete == true) */
1016 null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
1017 &error_abort);
1018- bdrv_graph_wrlock(NULL);
1019+ bdrv_graph_wrlock();
1020 bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA,
1021 &error_abort);
1022- bdrv_graph_wrunlock(NULL);
1023+ bdrv_graph_wrunlock();
1024
1025 blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
1026 blk_insert_bs(blk, bs, &error_abort);
1027@@ -1193,14 +1193,14 @@ static void no_coroutine_fn detach_indirect_bh(void *opaque)
1028
1029 bdrv_dec_in_flight(data->child_b->bs);
1030
1031- bdrv_graph_wrlock(NULL);
1032+ bdrv_graph_wrlock();
1033 bdrv_unref_child(data->parent_b, data->child_b);
1034
1035 bdrv_ref(data->c);
1036 data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C",
1037 &child_of_bds, BDRV_CHILD_DATA,
1038 &error_abort);
1039- bdrv_graph_wrunlock(NULL);
1040+ bdrv_graph_wrunlock();
1041 }
1042
1043 static void coroutine_mixed_fn detach_by_parent_aio_cb(void *opaque, int ret)
1044@@ -1298,7 +1298,7 @@ static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
1045 /* Set child relationships */
1046 bdrv_ref(b);
1047 bdrv_ref(a);
1048- bdrv_graph_wrlock(NULL);
1049+ bdrv_graph_wrlock();
1050 child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds,
1051 BDRV_CHILD_DATA, &error_abort);
1052 child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds,
1053@@ -1308,7 +1308,7 @@ static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
1054 bdrv_attach_child(parent_a, a, "PA-A",
1055 by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class,
1056 BDRV_CHILD_DATA, &error_abort);
1057- bdrv_graph_wrunlock(NULL);
1058+ bdrv_graph_wrunlock();
1059
1060 g_assert_cmpint(parent_a->refcnt, ==, 1);
1061 g_assert_cmpint(parent_b->refcnt, ==, 1);
1062@@ -1727,7 +1727,7 @@ static void test_drop_intermediate_poll(void)
1063 * Establish the chain last, so the chain links are the first
1064 * elements in the BDS.parents lists
1065 */
1066- bdrv_graph_wrlock(NULL);
1067+ bdrv_graph_wrlock();
1068 for (i = 0; i < 3; i++) {
1069 if (i) {
1070 /* Takes the reference to chain[i - 1] */
1071@@ -1735,7 +1735,7 @@ static void test_drop_intermediate_poll(void)
1072 &chain_child_class, BDRV_CHILD_COW, &error_abort);
1073 }
1074 }
1075- bdrv_graph_wrunlock(NULL);
1076+ bdrv_graph_wrunlock();
1077
1078 job = block_job_create("job", &test_simple_job_driver, NULL, job_node,
1079 0, BLK_PERM_ALL, 0, 0, NULL, NULL, &error_abort);
1080@@ -1982,10 +1982,10 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
1081 new_child_bs->total_sectors = 1;
1082
1083 bdrv_ref(old_child_bs);
1084- bdrv_graph_wrlock(NULL);
1085+ bdrv_graph_wrlock();
1086 bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
1087 BDRV_CHILD_COW, &error_abort);
1088- bdrv_graph_wrunlock(NULL);
1089+ bdrv_graph_wrunlock();
1090 parent_s->setup_completed = true;
1091
1092 for (i = 0; i < old_drain_count; i++) {
1093@@ -2016,9 +2016,9 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
1094 g_assert(parent_bs->quiesce_counter == old_drain_count);
1095 bdrv_drained_begin(old_child_bs);
1096 bdrv_drained_begin(new_child_bs);
1097- bdrv_graph_wrlock(NULL);
1098+ bdrv_graph_wrlock();
1099 bdrv_replace_node(old_child_bs, new_child_bs, &error_abort);
1100- bdrv_graph_wrunlock(NULL);
1101+ bdrv_graph_wrunlock();
1102 bdrv_drained_end(new_child_bs);
1103 bdrv_drained_end(old_child_bs);
1104 g_assert(parent_bs->quiesce_counter == new_drain_count);
1105diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
1106index 074adcbb9..8ee6ef38d 100644
1107--- a/tests/unit/test-bdrv-graph-mod.c
1108+++ b/tests/unit/test-bdrv-graph-mod.c
1109@@ -137,10 +137,10 @@ static void test_update_perm_tree(void)
1110
1111 blk_insert_bs(root, bs, &error_abort);
1112
1113- bdrv_graph_wrlock(NULL);
1114+ bdrv_graph_wrlock();
1115 bdrv_attach_child(filter, bs, "child", &child_of_bds,
1116 BDRV_CHILD_DATA, &error_abort);
1117- bdrv_graph_wrunlock(NULL);
1118+ bdrv_graph_wrunlock();
1119
1120 aio_context_acquire(qemu_get_aio_context());
1121 ret = bdrv_append(filter, bs, NULL);
1122@@ -206,11 +206,11 @@ static void test_should_update_child(void)
1123
1124 bdrv_set_backing_hd(target, bs, &error_abort);
1125
1126- bdrv_graph_wrlock(NULL);
1127+ bdrv_graph_wrlock();
1128 g_assert(target->backing->bs == bs);
1129 bdrv_attach_child(filter, target, "target", &child_of_bds,
1130 BDRV_CHILD_DATA, &error_abort);
1131- bdrv_graph_wrunlock(NULL);
1132+ bdrv_graph_wrunlock();
1133 aio_context_acquire(qemu_get_aio_context());
1134 bdrv_append(filter, bs, &error_abort);
1135 aio_context_release(qemu_get_aio_context());
1136@@ -248,7 +248,7 @@ static void test_parallel_exclusive_write(void)
1137 bdrv_ref(base);
1138 bdrv_ref(fl1);
1139
1140- bdrv_graph_wrlock(NULL);
1141+ bdrv_graph_wrlock();
1142 bdrv_attach_child(top, fl1, "backing", &child_of_bds,
1143 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
1144 &error_abort);
1145@@ -260,7 +260,7 @@ static void test_parallel_exclusive_write(void)
1146 &error_abort);
1147
1148 bdrv_replace_node(fl1, fl2, &error_abort);
1149- bdrv_graph_wrunlock(NULL);
1150+ bdrv_graph_wrunlock();
1151
1152 bdrv_drained_end(fl2);
1153 bdrv_drained_end(fl1);
1154@@ -367,7 +367,7 @@ static void test_parallel_perm_update(void)
1155 */
1156 bdrv_ref(base);
1157
1158- bdrv_graph_wrlock(NULL);
1159+ bdrv_graph_wrlock();
1160 bdrv_attach_child(top, ws, "file", &child_of_bds, BDRV_CHILD_DATA,
1161 &error_abort);
1162 c_fl1 = bdrv_attach_child(ws, fl1, "first", &child_of_bds,
1163@@ -380,7 +380,7 @@ static void test_parallel_perm_update(void)
1164 bdrv_attach_child(fl2, base, "backing", &child_of_bds,
1165 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
1166 &error_abort);
1167- bdrv_graph_wrunlock(NULL);
1168+ bdrv_graph_wrunlock();
1169
1170 /* Select fl1 as first child to be active */
1171 s->selected = c_fl1;
1172@@ -434,11 +434,11 @@ static void test_append_greedy_filter(void)
1173 BlockDriverState *base = no_perm_node("base");
1174 BlockDriverState *fl = exclusive_writer_node("fl1");
1175
1176- bdrv_graph_wrlock(NULL);
1177+ bdrv_graph_wrlock();
1178 bdrv_attach_child(top, base, "backing", &child_of_bds,
1179 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
1180 &error_abort);
1181- bdrv_graph_wrunlock(NULL);
1182+ bdrv_graph_wrunlock();
1183
1184 aio_context_acquire(qemu_get_aio_context());
1185 bdrv_append(fl, base, &error_abort);
1186--
11872.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0005.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0005.patch
new file mode 100644
index 0000000000..bcdd0fbed8
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0005.patch
@@ -0,0 +1,239 @@
1From 7ead946998610657d38d1a505d5f25300d4ca613 Mon Sep 17 00:00:00 2001
2From: Kevin Wolf <kwolf@redhat.com>
3Date: Thu, 25 Apr 2024 14:56:02 +0000
4Subject: [PATCH] block: Parse filenames only when explicitly requested
5
6When handling image filenames from legacy options such as -drive or from
7tools, these filenames are parsed for protocol prefixes, including for
8the json:{} pseudo-protocol.
9
10This behaviour is intended for filenames that come directly from the
11command line and for backing files, which may come from the image file
12itself. Higher level management tools generally take care to verify that
13untrusted images don't contain a bad (or any) backing file reference;
14'qemu-img info' is a suitable tool for this.
15
16However, for other files that can be referenced in images, such as
17qcow2 data files or VMDK extents, the string from the image file is
18usually not verified by management tools - and 'qemu-img info' wouldn't
19be suitable because in contrast to backing files, it already opens these
20other referenced files. So here the string should be interpreted as a
21literal local filename. More complex configurations need to be specified
22explicitly on the command line or in QMP...
23
24CVE: CVE-2024-4467
25Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/7ead946998610657d38d1a505d5f25300d4ca613]
26
27Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
28---
29 block.c | 94 ++++++++++++++++++++++++++++++++++-----------------------
30 1 file changed, 57 insertions(+), 37 deletions(-)
31
32diff --git a/block.c b/block.c
33index 25e1ebc60..f3cb32cd7 100644
34--- a/block.c
35+++ b/block.c
36@@ -86,6 +86,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
37 BlockDriverState *parent,
38 const BdrvChildClass *child_class,
39 BdrvChildRole child_role,
40+ bool parse_filename,
41 Error **errp);
42
43 static bool bdrv_recurse_has_child(BlockDriverState *bs,
44@@ -2047,7 +2048,8 @@ static void parse_json_protocol(QDict *options, const char **pfilename,
45 * block driver has been specified explicitly.
46 */
47 static int bdrv_fill_options(QDict **options, const char *filename,
48- int *flags, Error **errp)
49+ int *flags, bool allow_parse_filename,
50+ Error **errp)
51 {
52 const char *drvname;
53 bool protocol = *flags & BDRV_O_PROTOCOL;
54@@ -2089,7 +2091,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
55 if (protocol && filename) {
56 if (!qdict_haskey(*options, "filename")) {
57 qdict_put_str(*options, "filename", filename);
58- parse_filename = true;
59+ parse_filename = allow_parse_filename;
60 } else {
61 error_setg(errp, "Can't specify 'file' and 'filename' options at "
62 "the same time");
63@@ -3675,7 +3677,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
64 }
65
66 backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
67- &child_of_bds, bdrv_backing_role(bs), errp);
68+ &child_of_bds, bdrv_backing_role(bs), true,
69+ errp);
70 if (!backing_hd) {
71 bs->open_flags |= BDRV_O_NO_BACKING;
72 error_prepend(errp, "Could not open backing file: ");
73@@ -3712,7 +3715,8 @@ free_exit:
74 static BlockDriverState *
75 bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
76 BlockDriverState *parent, const BdrvChildClass *child_class,
77- BdrvChildRole child_role, bool allow_none, Error **errp)
78+ BdrvChildRole child_role, bool allow_none,
79+ bool parse_filename, Error **errp)
80 {
81 BlockDriverState *bs = NULL;
82 QDict *image_options;
83@@ -3743,7 +3747,8 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
84 }
85
86 bs = bdrv_open_inherit(filename, reference, image_options, 0,
87- parent, child_class, child_role, errp);
88+ parent, child_class, child_role, parse_filename,
89+ errp);
90 if (!bs) {
91 goto done;
92 }
93@@ -3753,6 +3758,33 @@ done:
94 return bs;
95 }
96
97+static BdrvChild *bdrv_open_child_common(const char *filename,
98+ QDict *options, const char *bdref_key,
99+ BlockDriverState *parent,
100+ const BdrvChildClass *child_class,
101+ BdrvChildRole child_role,
102+ bool allow_none, bool parse_filename,
103+ Error **errp)
104+{
105+ BlockDriverState *bs;
106+ BdrvChild *child;
107+
108+ GLOBAL_STATE_CODE();
109+
110+ bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
111+ child_role, allow_none, parse_filename, errp);
112+ if (bs == NULL) {
113+ return NULL;
114+ }
115+
116+ bdrv_graph_wrlock();
117+ child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
118+ errp);
119+ bdrv_graph_wrunlock();
120+
121+ return child;
122+}
123+
124 /*
125 * Opens a disk image whose options are given as BlockdevRef in another block
126 * device's options.
127@@ -3778,31 +3810,15 @@ BdrvChild *bdrv_open_child(const char *filename,
128 BdrvChildRole child_role,
129 bool allow_none, Error **errp)
130 {
131- BlockDriverState *bs;
132- BdrvChild *child;
133- AioContext *ctx;
134-
135- GLOBAL_STATE_CODE();
136-
137- bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
138- child_role, allow_none, errp);
139- if (bs == NULL) {
140- return NULL;
141- }
142-
143- bdrv_graph_wrlock();
144- ctx = bdrv_get_aio_context(bs);
145- aio_context_acquire(ctx);
146- child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
147- errp);
148- aio_context_release(ctx);
149- bdrv_graph_wrunlock();
150-
151- return child;
152+ return bdrv_open_child_common(filename, options, bdref_key, parent,
153+ child_class, child_role, allow_none, false,
154+ errp);
155 }
156
157 /*
158- * Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
159+ * This does mostly the same as bdrv_open_child(), but for opening the primary
160+ * child of a node. A notable difference from bdrv_open_child() is that it
161+ * enables filename parsing for protocol names (including json:).
162 *
163 * The caller must hold the lock of the main AioContext and no other AioContext.
164 * @parent can move to a different AioContext in this function. Callers must
165@@ -3819,8 +3835,8 @@ int bdrv_open_file_child(const char *filename,
166 role = parent->drv->is_filter ?
167 (BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY) : BDRV_CHILD_IMAGE;
168
169- if (!bdrv_open_child(filename, options, bdref_key, parent,
170- &child_of_bds, role, false, errp))
171+ if (!bdrv_open_child_common(filename, options, bdref_key, parent,
172+ &child_of_bds, role, false, true, errp))
173 {
174 return -EINVAL;
175 }
176@@ -3865,7 +3881,8 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
177
178 }
179
180- bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, errp);
181+ bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, false,
182+ errp);
183 obj = NULL;
184 qobject_unref(obj);
185 visit_free(v);
186@@ -3962,7 +3979,7 @@ static BlockDriverState * no_coroutine_fn
187 bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
188 int flags, BlockDriverState *parent,
189 const BdrvChildClass *child_class, BdrvChildRole child_role,
190- Error **errp)
191+ bool parse_filename, Error **errp)
192 {
193 int ret;
194 BlockBackend *file = NULL;
195@@ -4011,9 +4028,11 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
196 }
197
198 /* json: syntax counts as explicit options, as if in the QDict */
199- parse_json_protocol(options, &filename, &local_err);
200- if (local_err) {
201- goto fail;
202+ if (parse_filename) {
203+ parse_json_protocol(options, &filename, &local_err);
204+ if (local_err) {
205+ goto fail;
206+ }
207 }
208
209 bs->explicit_options = qdict_clone_shallow(options);
210@@ -4038,7 +4057,8 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
211 parent->open_flags, parent->options);
212 }
213
214- ret = bdrv_fill_options(&options, filename, &flags, &local_err);
215+ ret = bdrv_fill_options(&options, filename, &flags, parse_filename,
216+ &local_err);
217 if (ret < 0) {
218 goto fail;
219 }
220@@ -4107,7 +4127,7 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
221
222 file_bs = bdrv_open_child_bs(filename, options, "file", bs,
223 &child_of_bds, BDRV_CHILD_IMAGE,
224- true, &local_err);
225+ true, true, &local_err);
226 if (local_err) {
227 goto fail;
228 }
229@@ -4270,7 +4290,7 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
230 GLOBAL_STATE_CODE();
231
232 return bdrv_open_inherit(filename, reference, options, flags, NULL,
233- NULL, 0, errp);
234+ NULL, 0, true, errp);
235 }
236
237 /* Return true if the NULL-terminated @list contains @str */
238--
2392.40.0