qed: Implement .bdrv_drain
The "need_check_timer" is used to clear the "NEED_CHECK" flag in the image header after a grace period once metadata update has finished. In compliance to the bdrv_drain semantics we should make sure it remains deleted once .bdrv_drain is called. We cannot reuse qed_need_check_timer_cb because here it doesn't satisfy the assertion. Do the "plug" and "flush" calls manually. Signed-off-by: Fam Zheng <famz@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-id: 1447064214-29930-10-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
67da1dc5ce
commit
df9a681dc9
19
block.c
19
block.c
|
@ -3404,10 +3404,25 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
|||
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap)
|
||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
|
||||
{
|
||||
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
||||
hbitmap_reset_all(bitmap->bitmap);
|
||||
if (!out) {
|
||||
hbitmap_reset_all(bitmap->bitmap);
|
||||
} else {
|
||||
HBitmap *backup = bitmap->bitmap;
|
||||
bitmap->bitmap = hbitmap_alloc(bitmap->size,
|
||||
hbitmap_granularity(backup));
|
||||
*out = backup;
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
|
||||
{
|
||||
HBitmap *tmp = bitmap->bitmap;
|
||||
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
||||
bitmap->bitmap = in;
|
||||
hbitmap_free(tmp);
|
||||
}
|
||||
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
|
|
13
block/qed.c
13
block/qed.c
|
@ -375,6 +375,18 @@ static void bdrv_qed_attach_aio_context(BlockDriverState *bs,
|
|||
}
|
||||
}
|
||||
|
||||
static void bdrv_qed_drain(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
|
||||
/* Cancel timer and start doing I/O that were meant to happen as if it
|
||||
* fired, that way we get bdrv_drain() taking care of the ongoing requests
|
||||
* correctly. */
|
||||
qed_cancel_need_check_timer(s);
|
||||
qed_plug_allocating_write_reqs(s);
|
||||
bdrv_aio_flush(s->bs, qed_clear_need_check, s);
|
||||
}
|
||||
|
||||
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
|
@ -1676,6 +1688,7 @@ static BlockDriver bdrv_qed = {
|
|||
.bdrv_check = bdrv_qed_check,
|
||||
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
|
||||
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
|
||||
.bdrv_drain = bdrv_qed_drain,
|
||||
};
|
||||
|
||||
static void bdrv_qed_init(void)
|
||||
|
|
114
blockdev.c
114
blockdev.c
|
@ -1874,6 +1874,106 @@ static void blockdev_backup_clean(BlkTransactionState *common)
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct BlockDirtyBitmapState {
|
||||
BlkTransactionState common;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
HBitmap *backup;
|
||||
bool prepared;
|
||||
} BlockDirtyBitmapState;
|
||||
|
||||
static void block_dirty_bitmap_add_prepare(BlkTransactionState *common,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BlockDirtyBitmapAdd *action;
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
action = common->action->block_dirty_bitmap_add;
|
||||
/* AIO context taken and released within qmp_block_dirty_bitmap_add */
|
||||
qmp_block_dirty_bitmap_add(action->node, action->name,
|
||||
action->has_granularity, action->granularity,
|
||||
&local_err);
|
||||
|
||||
if (!local_err) {
|
||||
state->prepared = true;
|
||||
} else {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_add_abort(BlkTransactionState *common)
|
||||
{
|
||||
BlockDirtyBitmapAdd *action;
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
action = common->action->block_dirty_bitmap_add;
|
||||
/* Should not be able to fail: IF the bitmap was added via .prepare(),
|
||||
* then the node reference and bitmap name must have been valid.
|
||||
*/
|
||||
if (state->prepared) {
|
||||
qmp_block_dirty_bitmap_remove(action->node, action->name, &error_abort);
|
||||
}
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_clear_prepare(BlkTransactionState *common,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
BlockDirtyBitmap *action;
|
||||
|
||||
action = common->action->block_dirty_bitmap_clear;
|
||||
state->bitmap = block_dirty_bitmap_lookup(action->node,
|
||||
action->name,
|
||||
&state->bs,
|
||||
&state->aio_context,
|
||||
errp);
|
||||
if (!state->bitmap) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_dirty_bitmap_frozen(state->bitmap)) {
|
||||
error_setg(errp, "Cannot modify a frozen bitmap");
|
||||
return;
|
||||
} else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) {
|
||||
error_setg(errp, "Cannot clear a disabled bitmap");
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
|
||||
/* AioContext is released in .clean() */
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_clear_abort(BlkTransactionState *common)
|
||||
{
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
bdrv_undo_clear_dirty_bitmap(state->bitmap, state->backup);
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_clear_commit(BlkTransactionState *common)
|
||||
{
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
hbitmap_free(state->backup);
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_clear_clean(BlkTransactionState *common)
|
||||
{
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
if (state->aio_context) {
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void abort_prepare(BlkTransactionState *common, Error **errp)
|
||||
{
|
||||
error_setg(errp, "Transaction aborted using Abort action");
|
||||
|
@ -1921,6 +2021,18 @@ static const BdrvActionOps actions[] = {
|
|||
.abort = internal_snapshot_abort,
|
||||
.clean = internal_snapshot_clean,
|
||||
},
|
||||
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ADD] = {
|
||||
.instance_size = sizeof(BlockDirtyBitmapState),
|
||||
.prepare = block_dirty_bitmap_add_prepare,
|
||||
.abort = block_dirty_bitmap_add_abort,
|
||||
},
|
||||
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_CLEAR] = {
|
||||
.instance_size = sizeof(BlockDirtyBitmapState),
|
||||
.prepare = block_dirty_bitmap_clear_prepare,
|
||||
.commit = block_dirty_bitmap_clear_commit,
|
||||
.abort = block_dirty_bitmap_clear_abort,
|
||||
.clean = block_dirty_bitmap_clear_clean,
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2472,7 +2584,7 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
|
|||
goto out;
|
||||
}
|
||||
|
||||
bdrv_clear_dirty_bitmap(bitmap);
|
||||
bdrv_clear_dirty_bitmap(bitmap, NULL);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
|
|
|
@ -97,11 +97,7 @@ which is included at the end of this document.
|
|||
}
|
||||
```
|
||||
|
||||
## Transactions (Not yet implemented)
|
||||
|
||||
* Transactional commands are forthcoming in a future version,
|
||||
and are not yet available for use. This section serves as
|
||||
documentation of intent for their design and usage.
|
||||
## Transactions
|
||||
|
||||
### Justification
|
||||
|
||||
|
|
|
@ -501,7 +501,6 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
|||
int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap);
|
||||
void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
|
||||
void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
|
||||
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
|
||||
|
|
|
@ -693,4 +693,7 @@ void blk_dev_resize_cb(BlockBackend *blk);
|
|||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
|
||||
bool bdrv_requests_pending(BlockDriverState *bs);
|
||||
|
||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
|
||||
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
|
||||
|
||||
#endif /* BLOCK_INT_H */
|
||||
|
|
|
@ -1546,6 +1546,8 @@
|
|||
# blockdev-snapshot-internal-sync since 1.7
|
||||
# blockdev-backup since 2.3
|
||||
# blockdev-snapshot since 2.5
|
||||
# block-dirty-bitmap-add since 2.5
|
||||
# block-dirty-bitmap-clear since 2.5
|
||||
##
|
||||
{ 'union': 'TransactionAction',
|
||||
'data': {
|
||||
|
@ -1554,7 +1556,9 @@
|
|||
'drive-backup': 'DriveBackup',
|
||||
'blockdev-backup': 'BlockdevBackup',
|
||||
'abort': 'Abort',
|
||||
'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal'
|
||||
'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal',
|
||||
'block-dirty-bitmap-add': 'BlockDirtyBitmapAdd',
|
||||
'block-dirty-bitmap-clear': 'BlockDirtyBitmap'
|
||||
} }
|
||||
|
||||
##
|
||||
|
|
Loading…
Reference in a new issue