mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 11:39:53 +00:00
qcow2: Fix corruption bug in qcow2_detect_metadata_preallocation()
qcow2_detect_metadata_preallocation() calls qcow2_get_refcount() which
requires s->lock to be taken to protect its accesses to the refcount
table and refcount blocks. However, nothing in this code path actually
took the lock. This could cause the same cache entry to be used by two
requests at the same time, for different tables at different offsets,
resulting in image corruption.
As it would be preferable to base the detection on consistent data (even
though it's just heuristics), let's take the lock not only around the
qcow2_get_refcount() calls, but around the whole function.
This patch takes the lock in qcow2_co_block_status() earlier and asserts
in qcow2_detect_metadata_preallocation() that we hold the lock.
Fixes: 69f47505ee
Cc: qemu-stable@nongnu.org
Reported-by: Michael Weiser <michael.weiser@gmx.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Tested-by: Michael Weiser <michael.weiser@gmx.de>
Reviewed-by: Michael Weiser <michael.weiser@gmx.de>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
944f3d5dd2
commit
5e97855052
@ -3455,6 +3455,8 @@ int qcow2_detect_metadata_preallocation(BlockDriverState *bs)
|
|||||||
int64_t i, end_cluster, cluster_count = 0, threshold;
|
int64_t i, end_cluster, cluster_count = 0, threshold;
|
||||||
int64_t file_length, real_allocation, real_clusters;
|
int64_t file_length, real_allocation, real_clusters;
|
||||||
|
|
||||||
|
qemu_co_mutex_assert_locked(&s->lock);
|
||||||
|
|
||||||
file_length = bdrv_getlength(bs->file->bs);
|
file_length = bdrv_getlength(bs->file->bs);
|
||||||
if (file_length < 0) {
|
if (file_length < 0) {
|
||||||
return file_length;
|
return file_length;
|
||||||
|
@ -1916,6 +1916,8 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
|
|||||||
unsigned int bytes;
|
unsigned int bytes;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
|
qemu_co_mutex_lock(&s->lock);
|
||||||
|
|
||||||
if (!s->metadata_preallocation_checked) {
|
if (!s->metadata_preallocation_checked) {
|
||||||
ret = qcow2_detect_metadata_preallocation(bs);
|
ret = qcow2_detect_metadata_preallocation(bs);
|
||||||
s->metadata_preallocation = (ret == 1);
|
s->metadata_preallocation = (ret == 1);
|
||||||
@ -1923,7 +1925,6 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bytes = MIN(INT_MAX, count);
|
bytes = MIN(INT_MAX, count);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
|
||||||
ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
|
ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user