block/dirty-bitmap: add readonly field to BdrvDirtyBitmap

It will be needed in following commits for persistent bitmaps.
If bitmap is loaded from read-only storage (and we can't mark it
"in use" in this storage) corresponding BdrvDirtyBitmap should be
read-only.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-id: 20170628120530.31251-11-vsementsov@virtuozzo.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Vladimir Sementsov-Ogievskiy 2017-06-28 15:05:10 +03:00 committed by Max Reitz
parent 8bfc932e1e
commit d6883bc968
4 changed files with 54 additions and 0 deletions

View File

@ -46,6 +46,12 @@ struct BdrvDirtyBitmap {
bool disabled; /* Bitmap is disabled. It ignores all writes to bool disabled; /* Bitmap is disabled. It ignores all writes to
the device */ the device */
int active_iterators; /* How many iterators are active */ int active_iterators; /* How many iterators are active */
bool readonly; /* Bitmap is read-only. This field also
prevents the respective image from being
modified (i.e. blocks writes and discards).
Such operations must fail and both the image
and this bitmap must remain unchanged while
this flag is set. */
QLIST_ENTRY(BdrvDirtyBitmap) list; QLIST_ENTRY(BdrvDirtyBitmap) list;
}; };
@ -505,6 +511,7 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors) int64_t cur_sector, int64_t nr_sectors)
{ {
assert(bdrv_dirty_bitmap_enabled(bitmap)); assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors); hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
} }
@ -521,6 +528,7 @@ void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors) int64_t cur_sector, int64_t nr_sectors)
{ {
assert(bdrv_dirty_bitmap_enabled(bitmap)); assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors); hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
} }
@ -535,6 +543,7 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *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));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
bdrv_dirty_bitmap_lock(bitmap); bdrv_dirty_bitmap_lock(bitmap);
if (!out) { if (!out) {
hbitmap_reset_all(bitmap->bitmap); hbitmap_reset_all(bitmap->bitmap);
@ -551,6 +560,7 @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
{ {
HBitmap *tmp = bitmap->bitmap; HBitmap *tmp = bitmap->bitmap;
assert(bdrv_dirty_bitmap_enabled(bitmap)); assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
bitmap->bitmap = in; bitmap->bitmap = in;
hbitmap_free(tmp); hbitmap_free(tmp);
} }
@ -613,6 +623,7 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
if (!bdrv_dirty_bitmap_enabled(bitmap)) { if (!bdrv_dirty_bitmap_enabled(bitmap)) {
continue; continue;
} }
assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors); hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
} }
bdrv_dirty_bitmaps_unlock(bs); bdrv_dirty_bitmaps_unlock(bs);
@ -635,3 +646,28 @@ int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
{ {
return hbitmap_count(bitmap->meta); return hbitmap_count(bitmap->meta);
} }
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap)
{
return bitmap->readonly;
}
/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value)
{
qemu_mutex_lock(bitmap->mutex);
bitmap->readonly = value;
qemu_mutex_unlock(bitmap->mutex);
}
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
{
BdrvDirtyBitmap *bm;
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
if (bm->readonly) {
return true;
}
}
return false;
}

View File

@ -1315,6 +1315,10 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
uint64_t bytes_remaining = bytes; uint64_t bytes_remaining = bytes;
int max_transfer; int max_transfer;
if (bdrv_has_readonly_bitmaps(bs)) {
return -EPERM;
}
assert(is_power_of_2(align)); assert(is_power_of_2(align));
assert((offset & (align - 1)) == 0); assert((offset & (align - 1)) == 0);
assert((bytes & (align - 1)) == 0); assert((bytes & (align - 1)) == 0);
@ -2287,6 +2291,10 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
return -ENOMEDIUM; return -ENOMEDIUM;
} }
if (bdrv_has_readonly_bitmaps(bs)) {
return -EPERM;
}
ret = bdrv_check_byte_request(bs, offset, bytes); ret = bdrv_check_byte_request(bs, offset, bytes);
if (ret < 0) { if (ret < 0) {
return ret; return ret;

View File

@ -2033,6 +2033,9 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
} else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) { } else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) {
error_setg(errp, "Cannot clear a disabled bitmap"); error_setg(errp, "Cannot clear a disabled bitmap");
return; return;
} else if (bdrv_dirty_bitmap_readonly(state->bitmap)) {
error_setg(errp, "Cannot clear a readonly bitmap");
return;
} }
bdrv_clear_dirty_bitmap(state->bitmap, &state->backup); bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
@ -2779,6 +2782,9 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
"Bitmap '%s' is currently disabled and cannot be cleared", "Bitmap '%s' is currently disabled and cannot be cleared",
name); name);
return; return;
} else if (bdrv_dirty_bitmap_readonly(bitmap)) {
error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name);
return;
} }
bdrv_clear_dirty_bitmap(bitmap, NULL); bdrv_clear_dirty_bitmap(bitmap, NULL);

View File

@ -71,6 +71,8 @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
bool finish); bool finish);
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value);
/* Functions that require manual locking. */ /* Functions that require manual locking. */
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap); void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
@ -85,5 +87,7 @@ void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap); int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap); int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs); void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
#endif #endif