@@ -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 && bitnum + 8 <= last) {
+ 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,
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 <charlie@ctshepherd.com> --- block/cow.c | 79 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 38 deletions(-)