block: protect modification of dirty bitmaps with a mutex

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20170605123908.18777-17-pbonzini@redhat.com>
Signed-off-by: Fam Zheng <famz@redhat.com>
This commit is contained in:
Paolo Bonzini 2017-06-05 14:39:05 +02:00 committed by Fam Zheng
parent c0bad49946
commit b64bd51efa
5 changed files with 95 additions and 25 deletions

View File

@ -37,6 +37,7 @@
* or enabled. A frozen bitmap can only abdicate() or reclaim(). * or enabled. A frozen bitmap can only abdicate() or reclaim().
*/ */
struct BdrvDirtyBitmap { struct BdrvDirtyBitmap {
QemuMutex *mutex;
HBitmap *bitmap; /* Dirty sector bitmap implementation */ HBitmap *bitmap; /* Dirty sector bitmap implementation */
HBitmap *meta; /* Meta dirty bitmap */ HBitmap *meta; /* Meta dirty bitmap */
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */ BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
@ -62,6 +63,16 @@ static inline void bdrv_dirty_bitmaps_unlock(BlockDriverState *bs)
qemu_mutex_unlock(&bs->dirty_bitmap_mutex); qemu_mutex_unlock(&bs->dirty_bitmap_mutex);
} }
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap)
{
qemu_mutex_lock(bitmap->mutex);
}
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap)
{
qemu_mutex_unlock(bitmap->mutex);
}
/* Called with BQL or dirty_bitmap lock taken. */ /* Called with BQL or dirty_bitmap lock taken. */
BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name) BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
{ {
@ -109,6 +120,7 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
return NULL; return NULL;
} }
bitmap = g_new0(BdrvDirtyBitmap, 1); bitmap = g_new0(BdrvDirtyBitmap, 1);
bitmap->mutex = &bs->dirty_bitmap_mutex;
bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity)); bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
bitmap->size = bitmap_size; bitmap->size = bitmap_size;
bitmap->name = g_strdup(name); bitmap->name = g_strdup(name);
@ -134,20 +146,24 @@ void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
int chunk_size) int chunk_size)
{ {
assert(!bitmap->meta); assert(!bitmap->meta);
qemu_mutex_lock(bitmap->mutex);
bitmap->meta = hbitmap_create_meta(bitmap->bitmap, bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
chunk_size * BITS_PER_BYTE); chunk_size * BITS_PER_BYTE);
qemu_mutex_unlock(bitmap->mutex);
} }
void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap) void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
{ {
assert(bitmap->meta); assert(bitmap->meta);
qemu_mutex_lock(bitmap->mutex);
hbitmap_free_meta(bitmap->bitmap); hbitmap_free_meta(bitmap->bitmap);
bitmap->meta = NULL; bitmap->meta = NULL;
qemu_mutex_unlock(bitmap->mutex);
} }
int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs, int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, int64_t sector, BdrvDirtyBitmap *bitmap, int64_t sector,
int nb_sectors) int nb_sectors)
{ {
uint64_t i; uint64_t i;
int sectors_per_bit = 1 << hbitmap_granularity(bitmap->meta); int sectors_per_bit = 1 << hbitmap_granularity(bitmap->meta);
@ -162,11 +178,26 @@ int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
return false; return false;
} }
int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, int64_t sector,
int nb_sectors)
{
bool dirty;
qemu_mutex_lock(bitmap->mutex);
dirty = bdrv_dirty_bitmap_get_meta_locked(bs, bitmap, sector, nb_sectors);
qemu_mutex_unlock(bitmap->mutex);
return dirty;
}
void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs, void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, int64_t sector, BdrvDirtyBitmap *bitmap, int64_t sector,
int nb_sectors) int nb_sectors)
{ {
qemu_mutex_lock(bitmap->mutex);
hbitmap_reset(bitmap->meta, sector, nb_sectors); hbitmap_reset(bitmap->meta, sector, nb_sectors);
qemu_mutex_unlock(bitmap->mutex);
} }
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap) int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
@ -393,8 +424,9 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
return list; return list;
} }
int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, /* Called within bdrv_dirty_bitmap_lock..unlock */
int64_t sector) int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
int64_t sector)
{ {
if (bitmap) { if (bitmap) {
return hbitmap_get(bitmap->bitmap, sector); return hbitmap_get(bitmap->bitmap, sector);
@ -467,23 +499,42 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
return hbitmap_iter_next(&iter->hbi); return hbitmap_iter_next(&iter->hbi);
} }
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap, /* Called within bdrv_dirty_bitmap_lock..unlock */
int64_t cur_sector, int64_t nr_sectors) void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors)
{ {
assert(bdrv_dirty_bitmap_enabled(bitmap)); assert(bdrv_dirty_bitmap_enabled(bitmap));
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors); hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
} }
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors) int64_t cur_sector, int64_t nr_sectors)
{
bdrv_dirty_bitmap_lock(bitmap);
bdrv_set_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
bdrv_dirty_bitmap_unlock(bitmap);
}
/* Called within bdrv_dirty_bitmap_lock..unlock */
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors)
{ {
assert(bdrv_dirty_bitmap_enabled(bitmap)); assert(bdrv_dirty_bitmap_enabled(bitmap));
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors); hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
} }
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors)
{
bdrv_dirty_bitmap_lock(bitmap);
bdrv_reset_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
bdrv_dirty_bitmap_unlock(bitmap);
}
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out) void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
{ {
assert(bdrv_dirty_bitmap_enabled(bitmap)); assert(bdrv_dirty_bitmap_enabled(bitmap));
bdrv_dirty_bitmap_lock(bitmap);
if (!out) { if (!out) {
hbitmap_reset_all(bitmap->bitmap); hbitmap_reset_all(bitmap->bitmap);
} else { } else {
@ -492,6 +543,7 @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
hbitmap_granularity(backup)); hbitmap_granularity(backup));
*out = backup; *out = backup;
} }
bdrv_dirty_bitmap_unlock(bitmap);
} }
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in) void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)

View File

@ -342,6 +342,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
int max_io_sectors = MAX((s->buf_size >> BDRV_SECTOR_BITS) / MAX_IN_FLIGHT, int max_io_sectors = MAX((s->buf_size >> BDRV_SECTOR_BITS) / MAX_IN_FLIGHT,
MAX_IO_SECTORS); MAX_IO_SECTORS);
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
sector_num = bdrv_dirty_iter_next(s->dbi); sector_num = bdrv_dirty_iter_next(s->dbi);
if (sector_num < 0) { if (sector_num < 0) {
bdrv_set_dirty_iter(s->dbi, 0); bdrv_set_dirty_iter(s->dbi, 0);
@ -349,6 +350,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap)); trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
assert(sector_num >= 0); assert(sector_num >= 0);
} }
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
first_chunk = sector_num / sectors_per_chunk; first_chunk = sector_num / sectors_per_chunk;
while (test_bit(first_chunk, s->in_flight_bitmap)) { while (test_bit(first_chunk, s->in_flight_bitmap)) {
@ -360,12 +362,13 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
/* Find the number of consective dirty chunks following the first dirty /* Find the number of consective dirty chunks following the first dirty
* one, and wait for in flight requests in them. */ * one, and wait for in flight requests in them. */
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
while (nb_chunks * sectors_per_chunk < (s->buf_size >> BDRV_SECTOR_BITS)) { while (nb_chunks * sectors_per_chunk < (s->buf_size >> BDRV_SECTOR_BITS)) {
int64_t next_dirty; int64_t next_dirty;
int64_t next_sector = sector_num + nb_chunks * sectors_per_chunk; int64_t next_sector = sector_num + nb_chunks * sectors_per_chunk;
int64_t next_chunk = next_sector / sectors_per_chunk; int64_t next_chunk = next_sector / sectors_per_chunk;
if (next_sector >= end || if (next_sector >= end ||
!bdrv_get_dirty(source, s->dirty_bitmap, next_sector)) { !bdrv_get_dirty_locked(source, s->dirty_bitmap, next_sector)) {
break; break;
} }
if (test_bit(next_chunk, s->in_flight_bitmap)) { if (test_bit(next_chunk, s->in_flight_bitmap)) {
@ -386,8 +389,10 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
* calling bdrv_get_block_status_above could yield - if some blocks are * calling bdrv_get_block_status_above could yield - if some blocks are
* marked dirty in this window, we need to know. * marked dirty in this window, we need to know.
*/ */
bdrv_reset_dirty_bitmap(s->dirty_bitmap, sector_num, bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, sector_num,
nb_chunks * sectors_per_chunk); nb_chunks * sectors_per_chunk);
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
bitmap_set(s->in_flight_bitmap, sector_num / sectors_per_chunk, nb_chunks); bitmap_set(s->in_flight_bitmap, sector_num / sectors_per_chunk, nb_chunks);
while (nb_chunks > 0 && sector_num < end) { while (nb_chunks > 0 && sector_num < end) {
int64_t ret; int64_t ret;

View File

@ -611,8 +611,8 @@ struct BlockDriverState {
/* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex. /* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex.
* Reading from the list can be done with either the BQL or the * Reading from the list can be done with either the BQL or the
* dirty_bitmap_mutex. Modifying a bitmap requires the AioContext * dirty_bitmap_mutex. Modifying a bitmap only requires
* lock. */ * dirty_bitmap_mutex. */
QemuMutex dirty_bitmap_mutex; QemuMutex dirty_bitmap_mutex;
QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;

View File

@ -36,8 +36,6 @@ bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap); const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap); int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap);
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap); DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
int64_t sector);
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap, void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors); int64_t cur_sector, int64_t nr_sectors);
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
@ -45,6 +43,9 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs, int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, int64_t sector, BdrvDirtyBitmap *bitmap, int64_t sector,
int nb_sectors); int nb_sectors);
int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, int64_t sector,
int nb_sectors);
void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs, void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, int64_t sector, BdrvDirtyBitmap *bitmap, int64_t sector,
int nb_sectors); int nb_sectors);
@ -52,11 +53,6 @@ BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap, BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
uint64_t first_sector); uint64_t first_sector);
void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter); void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap, uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
uint64_t start, uint64_t count); uint64_t start, uint64_t count);
@ -72,4 +68,19 @@ void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
bool finish); bool finish);
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
/* Functions that require manual locking. */
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
int64_t sector);
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors);
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors);
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
#endif #endif

View File

@ -525,14 +525,15 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
} else { } else {
blk_mig_unlock(); blk_mig_unlock();
} }
if (bdrv_get_dirty(bs, bmds->dirty_bitmap, sector)) { bdrv_dirty_bitmap_lock(bmds->dirty_bitmap);
if (bdrv_get_dirty_locked(bs, bmds->dirty_bitmap, sector)) {
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
nr_sectors = total_sectors - sector; nr_sectors = total_sectors - sector;
} else { } else {
nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK; nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
} }
bdrv_reset_dirty_bitmap(bmds->dirty_bitmap, sector, nr_sectors); bdrv_reset_dirty_bitmap_locked(bmds->dirty_bitmap, sector, nr_sectors);
bdrv_dirty_bitmap_unlock(bmds->dirty_bitmap);
blk = g_new(BlkMigBlock, 1); blk = g_new(BlkMigBlock, 1);
blk->buf = g_malloc(BLOCK_SIZE); blk->buf = g_malloc(BLOCK_SIZE);
@ -568,9 +569,10 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
sector += nr_sectors; sector += nr_sectors;
bmds->cur_dirty = sector; bmds->cur_dirty = sector;
break; break;
} }
bdrv_dirty_bitmap_unlock(bmds->dirty_bitmap);
sector += BDRV_SECTORS_PER_DIRTY_CHUNK; sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
bmds->cur_dirty = sector; bmds->cur_dirty = sector;
} }