COW: Extend checking allocated bits to beyond one sector

cow_co_is_allocated() only checks one sector's worth of allocated bits
before returning. This is allowed but (slightly) inefficient, so extend
it to check all of the file's metadata sectors.

Signed-off-by: Charlie Shepherd <charlie@ctshepherd.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>

[kwolf: silenced compiler warning (-Wmaybe-uninitialized for changed)]
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Charlie Shepherd 2013-11-15 19:47:02 +01:00 committed by Kevin Wolf
parent 14b98fdaf3
commit 091b1108ca

View File

@ -152,18 +152,34 @@ static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs,
{ {
int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8; int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8;
uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE; uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
uint8_t bitmap[BDRV_SECTOR_SIZE]; bool first = true;
int changed = 0, same = 0;
do {
int ret; int ret;
int changed; uint8_t bitmap[BDRV_SECTOR_SIZE];
bitnum &= BITS_PER_BITMAP_SECTOR - 1;
int sector_bits = MIN(nb_sectors, BITS_PER_BITMAP_SECTOR - bitnum);
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap)); ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
bitnum &= BITS_PER_BITMAP_SECTOR - 1; if (first) {
changed = cow_test_bit(bitnum, bitmap); changed = cow_test_bit(bitnum, bitmap);
*num_same = cow_find_streak(bitmap, changed, bitnum, nb_sectors); first = false;
}
same += cow_find_streak(bitmap, changed, bitnum, nb_sectors);
bitnum += sector_bits;
nb_sectors -= sector_bits;
offset += BDRV_SECTOR_SIZE;
} while (nb_sectors);
*num_same = same;
return changed; return changed;
} }