184581fa4d
When a write request needs to allocate new clusters (or change the L2 bitmap of existing ones) a QCowL2Meta structure is created so the L2 metadata can be later updated and any copy-on-write can be performed if necessary. A write request can span a region consisting of an arbitrary combination of previously unallocated and allocated clusters, and if the unallocated ones can be put contiguous to the existing ones then QEMU will do so in order to minimize the number of write operations. In practice this means that a write request has not just one but a number of QCowL2Meta structures. All of them are added to the cluster_allocs list that is stored in BDRVQcow2State and is used to detect overlapping requests. After the write request finishes all its associated QCowL2Meta are removed from that list. calculate_l2_meta() takes care of creating and putting those structures in the list, and qcow2_handle_l2meta() takes care of removing them. The problem is that the error path in handle_alloc() also tries to remove an item in that list, a remnant from the time when this was handled there (that code would not even be correct anymore because it only removes one struct and not all the ones from the same write request). This can trigger a double removal of the same item from the list, causing a crash. This is not easy to reproduce in practice because it requires that do_alloc_cluster_offset() fails after a successful previous allocation during the same write request, but it can be reproduced with the included test case. Signed-off-by: Alberto Garcia <berto@igalia.com> Message-Id: <3440a1c4d53c4fe48312b478c96accb338cbef7c.1599150873.git.berto@igalia.com> Signed-off-by: Max Reitz <mreitz@redhat.com>
17 lines
805 B
Plaintext
17 lines
805 B
Plaintext
QA output created by 305
|
|
### Create the image
|
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
|
|
### Fill the first refcount block and one data cluster from the second
|
|
wrote 126976/126976 bytes at offset 0
|
|
124 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
### Discard two of the last data clusters, leave one in the middle
|
|
discard 1024/1024 bytes at offset 123904
|
|
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
discard 1024/1024 bytes at offset 125952
|
|
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
### Corrupt the offset of the second refcount block
|
|
### Try to allocate the discarded clusters again
|
|
qcow2: Marking image as corrupt: Refblock offset 0x20600 unaligned (reftable index: 0x1); further corruption events will be suppressed
|
|
write failed: Input/output error
|
|
*** done
|