Il 06/11/2013 13:23, Charlie Shepherd ha scritto: > Process a whole sector's worth of COW bits by reading a sector, setting the > bits, then writing it > out again. Make sure we only flush once, before writing metadata. > > Signed-off-by: Charlie Shepherd <char...@ctshepherd.com> > --- > block/cow.c | 79 > ++++++++++++++++++++++++++++++++----------------------------- > 1 file changed, 41 insertions(+), 38 deletions(-) > > diff --git a/block/cow.c b/block/cow.c > index 909c3e7..66f1478 100644 > --- a/block/cow.c > +++ b/block/cow.c > @@ -103,40 +103,18 @@ static int cow_open(BlockDriverState *bs, QDict > *options, int flags, > return ret; > } > > -/* > - * XXX(hch): right now these functions are extremely inefficient. > - * We should just read the whole bitmap we'll need in one go instead. > - */ > -static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum, bool > *first) > +static inline void cow_set_bits(uint8_t *bitmap, int start, int64_t > nb_sectors) > { > - uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8; > - uint8_t bitmap; > - int ret; > - > - ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap)); > - if (ret < 0) { > - return ret; > - } > - > - if (bitmap & (1 << (bitnum % 8))) { > - return 0; > - } > - > - if (*first) { > - ret = bdrv_flush(bs->file); > - if (ret < 0) { > - return ret; > + int64_t bitnum = start, last = start + nb_sectors; > + while (bitnum < last) { > + if ((bitnum & 7) == 0) {
I think this is missing " && bitnum + 8 <= last" in the condition. Otherwise looks good. Paolo > + bitmap[bitnum / 8] = 0xFF; > + bitnum += 8; > + continue; > } > - *first = false; > - } > - > - bitmap |= (1 << (bitnum % 8)); > - > - ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap)); > - if (ret < 0) { > - return ret; > + bitmap[bitnum/8] |= (1 << (bitnum % 8)); > + bitnum++; > } > - return 0; > } > > #define BITS_PER_BITMAP_SECTOR (512 * 8) > @@ -204,18 +182,43 @@ static int64_t coroutine_fn > cow_co_get_block_status(BlockDriverState *bs, > static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num, > int nb_sectors) > { > - int error = 0; > - int i; > + int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8; > + uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE; > bool first = true; > > - for (i = 0; i < nb_sectors; i++) { > - error = cow_set_bit(bs, sector_num + i, &first); > - if (error) { > - break; > + while (nb_sectors) { > + int ret; > + 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)); > + if (ret < 0) { > + return ret; > } > + > + if (first) { > + ret = bdrv_flush(bs->file); > + if (ret < 0) { > + return ret; > + } > + first = false; > + } > + > + cow_set_bits(bitmap, bitnum, sector_bits); > + > + ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap)); > + if (ret < 0) { > + return ret; > + } > + > + bitnum += sector_bits; > + nb_sectors -= sector_bits; > + offset += BDRV_SECTOR_SIZE; > } > > - return error; > + return 0; > } > > static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num, >