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);
|
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));
|
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,
|
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,
|
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@ -1676,6 +1688,7 @@ static BlockDriver bdrv_qed = {
|
|||||||
.bdrv_check = bdrv_qed_check,
|
.bdrv_check = bdrv_qed_check,
|
||||||
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
|
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
|
||||||
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
|
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
|
||||||
|
.bdrv_drain = bdrv_qed_drain,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_qed_init(void)
|
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)
|
static void abort_prepare(BlkTransactionState *common, Error **errp)
|
||||||
{
|
{
|
||||||
error_setg(errp, "Transaction aborted using Abort action");
|
error_setg(errp, "Transaction aborted using Abort action");
|
||||||
@ -1921,6 +2021,18 @@ static const BdrvActionOps actions[] = {
|
|||||||
.abort = internal_snapshot_abort,
|
.abort = internal_snapshot_abort,
|
||||||
.clean = internal_snapshot_clean,
|
.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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_clear_dirty_bitmap(bitmap);
|
bdrv_clear_dirty_bitmap(bitmap, NULL);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
|
@ -97,11 +97,7 @@ which is included at the end of this document.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Transactions (Not yet implemented)
|
## Transactions
|
||||||
|
|
||||||
* 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.
|
|
||||||
|
|
||||||
### Justification
|
### Justification
|
||||||
|
|
||||||
|
@ -501,7 +501,6 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
|||||||
int64_t cur_sector, int nr_sectors);
|
int64_t cur_sector, int nr_sectors);
|
||||||
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int nr_sectors);
|
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_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
|
||||||
void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
|
void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
|
||||||
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
|
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);
|
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
|
||||||
bool bdrv_requests_pending(BlockDriverState *bs);
|
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 */
|
#endif /* BLOCK_INT_H */
|
||||||
|
@ -1546,6 +1546,8 @@
|
|||||||
# blockdev-snapshot-internal-sync since 1.7
|
# blockdev-snapshot-internal-sync since 1.7
|
||||||
# blockdev-backup since 2.3
|
# blockdev-backup since 2.3
|
||||||
# blockdev-snapshot since 2.5
|
# blockdev-snapshot since 2.5
|
||||||
|
# block-dirty-bitmap-add since 2.5
|
||||||
|
# block-dirty-bitmap-clear since 2.5
|
||||||
##
|
##
|
||||||
{ 'union': 'TransactionAction',
|
{ 'union': 'TransactionAction',
|
||||||
'data': {
|
'data': {
|
||||||
@ -1554,7 +1556,9 @@
|
|||||||
'drive-backup': 'DriveBackup',
|
'drive-backup': 'DriveBackup',
|
||||||
'blockdev-backup': 'BlockdevBackup',
|
'blockdev-backup': 'BlockdevBackup',
|
||||||
'abort': 'Abort',
|
'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 New Issue
Block a user