@samitouri / QOSamiQemu / commits / fe0f9e3ab2

qcow2: do not try to clear the dirty bit on a read-only node

qcow2_do_close() -> qcow2_inactivate() clears the dirty bit with a plain write to bs->file, unconditionally. A read-only node can still be dirty, inherited from an earlier writable session, and that write then hits a missing BLK_PERM_WRITE and asserts in bdrv_co_write_req_prepare() (block/io.c) on an entirely ordinary close -- closing is expected, the dirty bit on a read-only node is not. Skip the clear for read-only nodes, same as read access already does. Any other still-dirty node keeps the unguarded write: it is expected to hold write permission, and a missing one there is a bug worth seeing. Signed-off-by: Denis V. Lunev <den@openvz.org> CC: Kevin Wolf <kwolf@redhat.com> CC: Hanna Reitz <hreitz@redhat.com> Message-ID: <20260716153552.3376009-1-den@openvz.org> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Denis V. Lunev committed Jul 16, 2026 at 17:35 UTC fe0f9e3ab2a8112dd9671bbb91365feba683f755
3 files changed +19 -1
block/qcow2.c
+5 -1
@@ -2870,7 +2870,11 @@ static int GRAPH_RDLOCK qcow2_inactivate(BlockDriverState *bs)
2870 strerror(-ret));
2871 }
2872
2873 - if (result == 0) {
2873 + /*
2874 + * A read-only node cannot resolve an inherited dirty bit here;
2875 + * leave it dirty, same as plain read access already does.
2876 + */
2877 + if (result == 0 && !bdrv_is_read_only(bs)) {
2878 qcow2_mark_clean(bs);
2879 }
2880
tests/qemu-iotests/039
+11
@@ -84,6 +84,17 @@ $QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
84 # The dirty bit must be set
85 _qcow2_dump_header | grep incompatible_features
86
87 +echo
88 +echo "== Read-only open must not crash on close =="
89 +
90 +# We must not try to write the QCOW2 header to a read-only image.
91 +$QEMU_IMG info --image-opts \
92 + "driver=$IMGFMT,read-only=on,file.driver=file,file.filename=$TEST_IMG,file.read-only=off" \
93 + > /dev/null
94 +
95 +# The dirty bit must still be set: this open never wrote any guest data
96 +_qcow2_dump_header | grep incompatible_features
97 +
98 echo
99 echo "== Repairing the image file must succeed =="
100
tests/qemu-iotests/039.out
+3
@@ -24,6 +24,9 @@ read 512/512 bytes at offset 0
24 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
25 incompatible_features [0]
26
27 +== Read-only open must not crash on close ==
28 +incompatible_features [0]
29 +
30 == Repairing the image file must succeed ==
31 ERROR cluster 5 refcount=0 reference=1
32 Rebuilding refcount structure