block: Guard against NULL bs->drv

We currently do not guard everywhere against a NULL bs->drv where we
should be doing so.  Most of the places fixed here just do not care
about that case at all.

Some care implicitly, e.g. through a prior function call to
bdrv_getlength() which would always fail for an ejected BDS.  Add an
assert there to make it more obvious.

Other places seem to care, but do so insufficiently: Freeing clusters in
a qcow2 image is an error-free operation, but it may leave the image in
an unusable state anyway.  Giving qcow2_free_clusters() an error code is
not really viable, it is much easier to note that bs->drv may be NULL
even after a successful driver call.  This concerns bdrv_co_flush(), and
the way the check is added to bdrv_co_pdiscard() (in every iteration
instead of only once).

Finally, some places employ at least an assert(bs->drv); somewhere, that
may be reasonable (such as in the reopen code), but in
bdrv_has_zero_init(), it is definitely not.  Returning 0 there in case
of an ejected BDS saves us much headache instead.

Reported-by: R. Nageswara Sastry <nasastry@in.ibm.com>
Buglink: https://bugs.launchpad.net/qemu/+bug/1728660
Signed-off-by: Max Reitz <mreitz@redhat.com>
Message-id: 20171110203111.7666-4-mreitz@redhat.com
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Max Reitz 2017-11-10 21:31:09 +01:00
parent 93bbaf03ff
commit d470ad42ac
7 changed files with 130 additions and 3 deletions

View file

@ -337,6 +337,28 @@ $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
# Can't repair this yet (TODO: We can just deallocate the cluster)
echo
echo '=== Discarding with an unaligned refblock ==='
echo
_make_test_img 64M
$QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io
# Make our refblock unaligned
poke_file "$TEST_IMG" "$(($rt_offset))" "\x00\x00\x00\x00\x00\x00\x2a\x00"
# Now try to discard something that will be submitted as two requests
# (main part + tail)
$QEMU_IO -c "discard 0 65537" "$TEST_IMG"
echo '--- Repairing ---'
# Fails the first repair because the corruption prevents the check
# function from double-checking
# (Using -q for the first invocation, because otherwise the
# double-check error message appears above the summary for some
# reason -- so let's just hide the summary)
_check_test_img -q -r all
_check_test_img -r all
# success, all done
echo "*** done"
rm -f $seq.full

View file

@ -317,4 +317,35 @@ discard 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qcow2: Marking image as corrupt: Preallocated zero cluster offset 0x2a00 unaligned (guest offset: 0); further corruption events will be suppressed
write failed: Input/output error
=== Discarding with an unaligned refblock ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qcow2: Marking image as corrupt: Refblock offset 0x2a00 unaligned (reftable index: 0); further corruption events will be suppressed
qcow2_free_clusters failed: Input/output error
discard failed: No medium found
--- Repairing ---
ERROR refcount block 0 is not cluster aligned; refcount table entry corrupted
qcow2: Marking image as corrupt: Refblock offset 0x2a00 unaligned (reftable index: 0); further corruption events will be suppressed
Can't get refcount for cluster 0: Input/output error
Can't get refcount for cluster 1: Input/output error
Can't get refcount for cluster 2: Input/output error
Can't get refcount for cluster 3: Input/output error
Can't get refcount for cluster 4: Input/output error
Can't get refcount for cluster 5: Input/output error
Can't get refcount for cluster 6: Input/output error
Rebuilding refcount structure
Repairing cluster 1 refcount=1 reference=0
qemu-img: Check failed: No medium found
Leaked cluster 1 refcount=1 reference=0
Repairing cluster 1 refcount=1 reference=0
The following inconsistencies were found and repaired:
1 leaked clusters
0 corruptions
Double checking the fixed image now...
No errors were found on the image.
*** done