block: introduce dirty_bitmap_mutex

It protects only the list of dirty bitmaps; in the next patch we will
also protect their content.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20170605123908.18777-15-pbonzini@redhat.com>
Signed-off-by: Fam Zheng <famz@redhat.com>
This commit is contained in:
Paolo Bonzini 2017-06-05 14:39:03 +02:00 committed by Fam Zheng
parent 3783fa3dd3
commit 2119882c7e
6 changed files with 58 additions and 45 deletions

View File

@ -321,6 +321,7 @@ BlockDriverState *bdrv_new(void)
} }
notifier_with_return_list_init(&bs->before_write_notifiers); notifier_with_return_list_init(&bs->before_write_notifiers);
qemu_co_mutex_init(&bs->reqs_lock); qemu_co_mutex_init(&bs->reqs_lock);
qemu_mutex_init(&bs->dirty_bitmap_mutex);
bs->refcnt = 1; bs->refcnt = 1;
bs->aio_context = qemu_get_aio_context(); bs->aio_context = qemu_get_aio_context();

View File

@ -52,6 +52,17 @@ struct BdrvDirtyBitmapIter {
BdrvDirtyBitmap *bitmap; BdrvDirtyBitmap *bitmap;
}; };
static inline void bdrv_dirty_bitmaps_lock(BlockDriverState *bs)
{
qemu_mutex_lock(&bs->dirty_bitmap_mutex);
}
static inline void bdrv_dirty_bitmaps_unlock(BlockDriverState *bs)
{
qemu_mutex_unlock(&bs->dirty_bitmap_mutex);
}
/* 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)
{ {
BdrvDirtyBitmap *bm; BdrvDirtyBitmap *bm;
@ -65,6 +76,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
return NULL; return NULL;
} }
/* Called with BQL taken. */
void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap) void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
{ {
assert(!bdrv_dirty_bitmap_frozen(bitmap)); assert(!bdrv_dirty_bitmap_frozen(bitmap));
@ -72,6 +84,7 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
bitmap->name = NULL; bitmap->name = NULL;
} }
/* Called with BQL taken. */
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
uint32_t granularity, uint32_t granularity,
const char *name, const char *name,
@ -100,7 +113,9 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
bitmap->size = bitmap_size; bitmap->size = bitmap_size;
bitmap->name = g_strdup(name); bitmap->name = g_strdup(name);
bitmap->disabled = false; bitmap->disabled = false;
bdrv_dirty_bitmaps_lock(bs);
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list); QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
bdrv_dirty_bitmaps_unlock(bs);
return bitmap; return bitmap;
} }
@ -164,16 +179,19 @@ const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
return bitmap->name; return bitmap->name;
} }
/* Called with BQL taken. */
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap) bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
{ {
return bitmap->successor; return bitmap->successor;
} }
/* Called with BQL taken. */
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap) bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
{ {
return !(bitmap->disabled || bitmap->successor); return !(bitmap->disabled || bitmap->successor);
} }
/* Called with BQL taken. */
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap) DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
{ {
if (bdrv_dirty_bitmap_frozen(bitmap)) { if (bdrv_dirty_bitmap_frozen(bitmap)) {
@ -188,6 +206,7 @@ DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
/** /**
* Create a successor bitmap destined to replace this bitmap after an operation. * Create a successor bitmap destined to replace this bitmap after an operation.
* Requires that the bitmap is not frozen and has no successor. * Requires that the bitmap is not frozen and has no successor.
* Called with BQL taken.
*/ */
int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, Error **errp) BdrvDirtyBitmap *bitmap, Error **errp)
@ -220,6 +239,7 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
/** /**
* For a bitmap with a successor, yield our name to the successor, * For a bitmap with a successor, yield our name to the successor,
* delete the old bitmap, and return a handle to the new bitmap. * delete the old bitmap, and return a handle to the new bitmap.
* Called with BQL taken.
*/ */
BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, BdrvDirtyBitmap *bitmap,
@ -247,6 +267,7 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
* In cases of failure where we can no longer safely delete the parent, * In cases of failure where we can no longer safely delete the parent,
* we may wish to re-join the parent and child/successor. * we may wish to re-join the parent and child/successor.
* The merged parent will be un-frozen, but not explicitly re-enabled. * The merged parent will be un-frozen, but not explicitly re-enabled.
* Called with BQL taken.
*/ */
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
BdrvDirtyBitmap *parent, BdrvDirtyBitmap *parent,
@ -271,25 +292,30 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
/** /**
* Truncates _all_ bitmaps attached to a BDS. * Truncates _all_ bitmaps attached to a BDS.
* Called with BQL taken.
*/ */
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs) void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
{ {
BdrvDirtyBitmap *bitmap; BdrvDirtyBitmap *bitmap;
uint64_t size = bdrv_nb_sectors(bs); uint64_t size = bdrv_nb_sectors(bs);
bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) { QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
assert(!bdrv_dirty_bitmap_frozen(bitmap)); assert(!bdrv_dirty_bitmap_frozen(bitmap));
assert(!bitmap->active_iterators); assert(!bitmap->active_iterators);
hbitmap_truncate(bitmap->bitmap, size); hbitmap_truncate(bitmap->bitmap, size);
bitmap->size = size; bitmap->size = size;
} }
bdrv_dirty_bitmaps_unlock(bs);
} }
/* Called with BQL taken. */
static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs, static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, BdrvDirtyBitmap *bitmap,
bool only_named) bool only_named)
{ {
BdrvDirtyBitmap *bm, *next; BdrvDirtyBitmap *bm, *next;
bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) { QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) { if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) {
assert(!bm->active_iterators); assert(!bm->active_iterators);
@ -301,15 +327,19 @@ static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
g_free(bm); g_free(bm);
if (bitmap) { if (bitmap) {
return; goto out;
} }
} }
} }
if (bitmap) { if (bitmap) {
abort(); abort();
} }
out:
bdrv_dirty_bitmaps_unlock(bs);
} }
/* Called with BQL taken. */
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
{ {
bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false); bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false);
@ -318,18 +348,21 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
/** /**
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()). * Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
* There must not be any frozen bitmaps attached. * There must not be any frozen bitmaps attached.
* Called with BQL taken.
*/ */
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
{ {
bdrv_do_release_matching_dirty_bitmap(bs, NULL, true); bdrv_do_release_matching_dirty_bitmap(bs, NULL, true);
} }
/* Called with BQL taken. */
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
{ {
assert(!bdrv_dirty_bitmap_frozen(bitmap)); assert(!bdrv_dirty_bitmap_frozen(bitmap));
bitmap->disabled = true; bitmap->disabled = true;
} }
/* Called with BQL taken. */
void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap) void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
{ {
assert(!bdrv_dirty_bitmap_frozen(bitmap)); assert(!bdrv_dirty_bitmap_frozen(bitmap));
@ -342,6 +375,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
BlockDirtyInfoList *list = NULL; BlockDirtyInfoList *list = NULL;
BlockDirtyInfoList **plist = &list; BlockDirtyInfoList **plist = &list;
bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) { QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1); BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1); BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
@ -354,6 +388,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
*plist = entry; *plist = entry;
plist = &entry->next; plist = &entry->next;
} }
bdrv_dirty_bitmaps_unlock(bs);
return list; return list;
} }
@ -508,12 +543,19 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
int64_t nr_sectors) int64_t nr_sectors)
{ {
BdrvDirtyBitmap *bitmap; BdrvDirtyBitmap *bitmap;
if (QLIST_EMPTY(&bs->dirty_bitmaps)) {
return;
}
bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) { QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
if (!bdrv_dirty_bitmap_enabled(bitmap)) { if (!bdrv_dirty_bitmap_enabled(bitmap)) {
continue; continue;
} }
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors); hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
} }
bdrv_dirty_bitmaps_unlock(bs);
} }
/** /**

View File

@ -506,6 +506,8 @@ static void mirror_exit(BlockJob *job, void *opaque)
BlockDriverState *mirror_top_bs = s->mirror_top_bs; BlockDriverState *mirror_top_bs = s->mirror_top_bs;
Error *local_err = NULL; Error *local_err = NULL;
bdrv_release_dirty_bitmap(src, s->dirty_bitmap);
/* Make sure that the source BDS doesn't go away before we called /* Make sure that the source BDS doesn't go away before we called
* block_job_completed(). */ * block_job_completed(). */
bdrv_ref(src); bdrv_ref(src);
@ -904,7 +906,6 @@ immediate_exit:
g_free(s->cow_bitmap); g_free(s->cow_bitmap);
g_free(s->in_flight_bitmap); g_free(s->in_flight_bitmap);
bdrv_dirty_iter_free(s->dbi); bdrv_dirty_iter_free(s->dbi);
bdrv_release_dirty_bitmap(bs, s->dirty_bitmap);
data = g_malloc(sizeof(*data)); data = g_malloc(sizeof(*data));
data->ret = ret; data->ret = ret;

View File

@ -1362,12 +1362,10 @@ out_aio_context:
static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
const char *name, const char *name,
BlockDriverState **pbs, BlockDriverState **pbs,
AioContext **paio,
Error **errp) Error **errp)
{ {
BlockDriverState *bs; BlockDriverState *bs;
BdrvDirtyBitmap *bitmap; BdrvDirtyBitmap *bitmap;
AioContext *aio_context;
if (!node) { if (!node) {
error_setg(errp, "Node cannot be NULL"); error_setg(errp, "Node cannot be NULL");
@ -1383,29 +1381,17 @@ static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
return NULL; return NULL;
} }
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
bitmap = bdrv_find_dirty_bitmap(bs, name); bitmap = bdrv_find_dirty_bitmap(bs, name);
if (!bitmap) { if (!bitmap) {
error_setg(errp, "Dirty bitmap '%s' not found", name); error_setg(errp, "Dirty bitmap '%s' not found", name);
goto fail; return NULL;
} }
if (pbs) { if (pbs) {
*pbs = bs; *pbs = bs;
} }
if (paio) {
*paio = aio_context;
} else {
aio_context_release(aio_context);
}
return bitmap; return bitmap;
fail:
aio_context_release(aio_context);
return NULL;
} }
/* New and old BlockDriverState structs for atomic group operations */ /* New and old BlockDriverState structs for atomic group operations */
@ -2025,7 +2011,6 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
state->bitmap = block_dirty_bitmap_lookup(action->node, state->bitmap = block_dirty_bitmap_lookup(action->node,
action->name, action->name,
&state->bs, &state->bs,
&state->aio_context,
errp); errp);
if (!state->bitmap) { if (!state->bitmap) {
return; return;
@ -2733,7 +2718,6 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bool has_granularity, uint32_t granularity, bool has_granularity, uint32_t granularity,
Error **errp) Error **errp)
{ {
AioContext *aio_context;
BlockDriverState *bs; BlockDriverState *bs;
if (!name || name[0] == '\0') { if (!name || name[0] == '\0') {
@ -2746,14 +2730,11 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
return; return;
} }
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
if (has_granularity) { if (has_granularity) {
if (granularity < 512 || !is_power_of_2(granularity)) { if (granularity < 512 || !is_power_of_2(granularity)) {
error_setg(errp, "Granularity must be power of 2 " error_setg(errp, "Granularity must be power of 2 "
"and at least 512"); "and at least 512");
goto out; return;
} }
} else { } else {
/* Default to cluster size, if available: */ /* Default to cluster size, if available: */
@ -2761,19 +2742,15 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
} }
bdrv_create_dirty_bitmap(bs, granularity, name, errp); bdrv_create_dirty_bitmap(bs, granularity, name, errp);
out:
aio_context_release(aio_context);
} }
void qmp_block_dirty_bitmap_remove(const char *node, const char *name, void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
Error **errp) Error **errp)
{ {
AioContext *aio_context;
BlockDriverState *bs; BlockDriverState *bs;
BdrvDirtyBitmap *bitmap; BdrvDirtyBitmap *bitmap;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp); bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) { if (!bitmap || !bs) {
return; return;
} }
@ -2782,13 +2759,10 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
error_setg(errp, error_setg(errp,
"Bitmap '%s' is currently frozen and cannot be removed", "Bitmap '%s' is currently frozen and cannot be removed",
name); name);
goto out; return;
} }
bdrv_dirty_bitmap_make_anon(bitmap); bdrv_dirty_bitmap_make_anon(bitmap);
bdrv_release_dirty_bitmap(bs, bitmap); bdrv_release_dirty_bitmap(bs, bitmap);
out:
aio_context_release(aio_context);
} }
/** /**
@ -2798,11 +2772,10 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
void qmp_block_dirty_bitmap_clear(const char *node, const char *name, void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
Error **errp) Error **errp)
{ {
AioContext *aio_context;
BdrvDirtyBitmap *bitmap; BdrvDirtyBitmap *bitmap;
BlockDriverState *bs; BlockDriverState *bs;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp); bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) { if (!bitmap || !bs) {
return; return;
} }
@ -2811,18 +2784,15 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
error_setg(errp, error_setg(errp,
"Bitmap '%s' is currently frozen and cannot be modified", "Bitmap '%s' is currently frozen and cannot be modified",
name); name);
goto out; return;
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) { } else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
error_setg(errp, error_setg(errp,
"Bitmap '%s' is currently disabled and cannot be cleared", "Bitmap '%s' is currently disabled and cannot be cleared",
name); name);
goto out; return;
} }
bdrv_clear_dirty_bitmap(bitmap, NULL); bdrv_clear_dirty_bitmap(bitmap, NULL);
out:
aio_context_release(aio_context);
} }
void hmp_drive_del(Monitor *mon, const QDict *qdict) void hmp_drive_del(Monitor *mon, const QDict *qdict)

View File

@ -609,6 +609,11 @@ struct BlockDriverState {
uint64_t write_threshold_offset; uint64_t write_threshold_offset;
NotifierWithReturn write_threshold_notifier; NotifierWithReturn write_threshold_notifier;
/* 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
* dirty_bitmap_mutex. Modifying a bitmap requires the AioContext
* lock. */
QemuMutex dirty_bitmap_mutex;
QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
/* Offset after the highest byte written to */ /* Offset after the highest byte written to */

View File

@ -341,10 +341,8 @@ static int set_dirty_tracking(void)
int ret; int ret;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
aio_context_acquire(blk_get_aio_context(bmds->blk));
bmds->dirty_bitmap = bdrv_create_dirty_bitmap(blk_bs(bmds->blk), bmds->dirty_bitmap = bdrv_create_dirty_bitmap(blk_bs(bmds->blk),
BLOCK_SIZE, NULL, NULL); BLOCK_SIZE, NULL, NULL);
aio_context_release(blk_get_aio_context(bmds->blk));
if (!bmds->dirty_bitmap) { if (!bmds->dirty_bitmap) {
ret = -errno; ret = -errno;
goto fail; goto fail;
@ -355,9 +353,7 @@ static int set_dirty_tracking(void)
fail: fail:
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
if (bmds->dirty_bitmap) { if (bmds->dirty_bitmap) {
aio_context_acquire(blk_get_aio_context(bmds->blk));
bdrv_release_dirty_bitmap(blk_bs(bmds->blk), bmds->dirty_bitmap); bdrv_release_dirty_bitmap(blk_bs(bmds->blk), bmds->dirty_bitmap);
aio_context_release(blk_get_aio_context(bmds->blk));
} }
} }
return ret; return ret;
@ -370,9 +366,7 @@ static void unset_dirty_tracking(void)
BlkMigDevState *bmds; BlkMigDevState *bmds;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
aio_context_acquire(blk_get_aio_context(bmds->blk));
bdrv_release_dirty_bitmap(blk_bs(bmds->blk), bmds->dirty_bitmap); bdrv_release_dirty_bitmap(blk_bs(bmds->blk), bmds->dirty_bitmap);
aio_context_release(blk_get_aio_context(bmds->blk));
} }
} }