[PATCH 1/2] qcow2: do not clear the dirty bit when reopening a read-only node
"Denis V. Lunev" <[email protected]> Sat, 1 Aug 2026 00:00:38 +0200
| Newsgroups | org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
qcow2_reopen_prepare() clears the dirty bit whenever the node is reopened read-only, with an unguarded header write. A read-only node can still be dirty, inherited from an earlier writable session, and it holds no BLK_PERM_WRITE to resolve that. A read-only to read-only reopen of a dirty image therefore fails outright: $ qemu-io -r -f qcow2 dirty.qcow2 <<< $'reopen -r\nquit' qemu-io: failed while preparing to reopen image 'dirty.qcow2' Clear it only for a node that is writable now, the predicate qcow2_do_open() already uses for the repair. bdrv_is_writable() also excludes an inactive node, whose header must not be touched either. Signed-off-by: Denis V. Lunev <[email protected]> CC: Kevin Wolf <[email protected]> CC: Hanna Reitz <[email protected]> --- block/qcow2.c | 8 +++++--- tests/qemu-iotests/039 | 11 +++++++++++ tests/qemu-iotests/039.out | 5 +++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 7292dd036c..1543255eba 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2102,9 +2102,11 @@ qcow2_reopen_prepare(BDRVReopenState *state,BlockReopenQueue *queue, goto fail; } - ret = qcow2_mark_clean(state->bs); - if (ret < 0) { - goto fail; + if (bdrv_is_writable(state->bs)) { + ret = qcow2_mark_clean(state->bs); + if (ret < 0) { + goto fail; + } } } diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index 94a8bfe754..a5be81bc4a 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -95,6 +95,17 @@ $QEMU_IMG info --image-opts \ # The dirty bit must still be set: this open never wrote any guest data _qcow2_dump_header | grep incompatible_features +echo +echo "== Read-only reopen must not clear the dirty bit ==" + +# Reopening a read-only node must not try to write the QCOW2 header either, +# and must leave the dirty bit for whoever ends up repairing the image. +$QEMU_IO -r -c "reopen -r" -c "read -P 0x5a 0 512" "$TEST_IMG" \ + | _filter_qemu_io + +# The dirty bit must still be set +_qcow2_dump_header | grep incompatible_features + echo echo "== Repairing the image file must succeed ==" diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out index c66361128f..3c71e5a3dd 100644 --- a/tests/qemu-iotests/039.out +++ b/tests/qemu-iotests/039.out @@ -27,6 +27,11 @@ incompatible_features [0] == Read-only open must not crash on close == incompatible_features [0] +== Read-only reopen must not clear the dirty bit == +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +incompatible_features [0] + == Repairing the image file must succeed == ERROR cluster 5 refcount=0 reference=1 Rebuilding refcount structure -- 2.53.0