mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-30 21:42:06 -06:00
cow: make reads go at a decent speed
Do not do two reads for each sector; load each sector of the bitmap and use bitmap operations to process it. Writes are still dog slow! Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
0ca0b0d5f8
commit
276cbc7f2f
1 changed files with 32 additions and 22 deletions
54
block/cow.c
54
block/cow.c
|
@ -126,18 +126,31 @@ static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
|
#define BITS_PER_BITMAP_SECTOR (512 * 8)
|
||||||
|
|
||||||
|
/* Cannot use bitmap.c on big-endian machines. */
|
||||||
|
static int cow_test_bit(int64_t bitnum, const uint8_t *bitmap)
|
||||||
{
|
{
|
||||||
uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
|
return (bitmap[bitnum / 8] & (1 << (bitnum & 7))) != 0;
|
||||||
uint8_t bitmap;
|
}
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
static int cow_find_streak(const uint8_t *bitmap, int value, int start, int nb_sectors)
|
||||||
if (ret < 0) {
|
{
|
||||||
return ret;
|
int streak_value = value ? 0xFF : 0;
|
||||||
|
int last = MIN(start + nb_sectors, BITS_PER_BITMAP_SECTOR);
|
||||||
|
int bitnum = start;
|
||||||
|
while (bitnum < last) {
|
||||||
|
if ((bitnum & 7) == 0 && bitmap[bitnum / 8] == streak_value) {
|
||||||
|
bitnum += 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cow_test_bit(bitnum, bitmap) == value) {
|
||||||
|
bitnum++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return MIN(bitnum, last) - start;
|
||||||
return !!(bitmap & (1 << (bitnum % 8)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if first block has been changed (ie. current version is
|
/* Return true if first block has been changed (ie. current version is
|
||||||
|
@ -146,23 +159,20 @@ static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
|
||||||
static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs,
|
static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors, int *num_same)
|
int64_t sector_num, int nb_sectors, int *num_same)
|
||||||
{
|
{
|
||||||
|
int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8;
|
||||||
|
uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
|
||||||
|
uint8_t bitmap[BDRV_SECTOR_SIZE];
|
||||||
|
int ret;
|
||||||
int changed;
|
int changed;
|
||||||
|
|
||||||
if (nb_sectors == 0) {
|
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||||
*num_same = nb_sectors;
|
if (ret < 0) {
|
||||||
return 0;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
changed = is_bit_set(bs, sector_num);
|
|
||||||
if (changed < 0) {
|
|
||||||
return 0; /* XXX: how to return I/O errors? */
|
|
||||||
}
|
|
||||||
|
|
||||||
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
|
|
||||||
if (is_bit_set(bs, sector_num + *num_same) != changed)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
||||||
|
changed = cow_test_bit(bitnum, bitmap);
|
||||||
|
*num_same = cow_find_streak(bitmap, changed, bitnum, nb_sectors);
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue