mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/jnsnow/tags/bitmaps-pull-request' into staging
Pull request
Rebase notes:
011/36:[0003] [FC] 'block/backup: upgrade copy_bitmap to BdrvDirtyBitmap'
016/36:[----] [-C] 'iotests: Add virtio-scsi device helper'
017/36:[0002] [FC] 'iotests: add test 257 for bitmap-mode backups'
030/36:[0011] [FC] 'block/backup: teach TOP to never copy unallocated regions'
032/36:[0018] [FC] 'iotests/257: test traditional sync modes'
11: A new hbitmap call was added late in 4.1, changed to
bdrv_dirty_bitmap_next_zero.
16: Context-only (self.has_quit is new context in 040)
17: Removed 'auto' to follow upstream trends in iotest fashion
30: Handled explicitly on-list with R-B from Max.
32: Fix capitalization in test, as mentioned on-list.
# gpg: Signature made Sat 17 Aug 2019 00:12:13 BST
# gpg: using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [full]
# Primary key fingerprint: FAEB 9711 A12C F475 812F 18F2 88A9 064D 1835 61EB
# Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76 CBD0 7DEF 8106 AAFC 390E
* remotes/jnsnow/tags/bitmaps-pull-request: (36 commits)
tests/test-hbitmap: test next_zero and _next_dirty_area after truncate
block/backup: refactor write_flags
block/backup: deal with zero detection
qapi: add dirty-bitmaps to query-named-block-nodes result
iotests/257: test traditional sync modes
block/backup: support bitmap sync modes for non-bitmap backups
block/backup: teach TOP to never copy unallocated regions
block/backup: add backup_is_cluster_allocated
block/backup: centralize copy_bitmap initialization
block/backup: improve sync=bitmap work estimates
iotests/257: test API failures
block/backup: hoist bitmap check into QMP interface
iotests/257: Refactor backup helpers
iotests/257: add EmulatedBitmap class
iotests/257: add Pattern class
iotests: test bitmap moving inside 254
qapi: implement block-dirty-bitmap-remove transaction action
blockdev: reduce aio_context locked sections in bitmap add/remove
block/backup: loosen restriction on readonly bitmaps
iotests: add test 257 for bitmap-mode backups
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -5346,7 +5346,7 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
|
||||
for (bm = bdrv_dirty_bitmap_next(bs, NULL); bm;
|
||||
bm = bdrv_dirty_bitmap_next(bs, bm))
|
||||
{
|
||||
bdrv_dirty_bitmap_set_migration(bm, false);
|
||||
bdrv_dirty_bitmap_skip_store(bm, false);
|
||||
}
|
||||
|
||||
ret = refresh_total_sectors(bs, bs->total_sectors);
|
||||
|
||||
+206
-106
File diff suppressed because it is too large
Load Diff
+70
-22
@@ -48,10 +48,9 @@ struct BdrvDirtyBitmap {
|
||||
bool inconsistent; /* bitmap is persistent, but inconsistent.
|
||||
It cannot be used at all in any way, except
|
||||
a QMP user can remove it. */
|
||||
bool migration; /* Bitmap is selected for migration, it should
|
||||
not be stored on the next inactivation
|
||||
(persistent flag doesn't matter until next
|
||||
invalidation).*/
|
||||
bool skip_store; /* We are either migrating or deleting this
|
||||
* bitmap; it should not be stored on the next
|
||||
* inactivation. */
|
||||
QLIST_ENTRY(BdrvDirtyBitmap) list;
|
||||
};
|
||||
|
||||
@@ -509,14 +508,19 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||
bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t offset)
|
||||
bool bdrv_dirty_bitmap_get_locked(BdrvDirtyBitmap *bitmap, int64_t offset)
|
||||
{
|
||||
if (bitmap) {
|
||||
return hbitmap_get(bitmap->bitmap, offset);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return hbitmap_get(bitmap->bitmap, offset);
|
||||
}
|
||||
|
||||
bool bdrv_dirty_bitmap_get(BdrvDirtyBitmap *bitmap, int64_t offset)
|
||||
{
|
||||
bool ret;
|
||||
bdrv_dirty_bitmap_lock(bitmap);
|
||||
ret = bdrv_dirty_bitmap_get_locked(bitmap, offset);
|
||||
bdrv_dirty_bitmap_unlock(bitmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -757,16 +761,16 @@ void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap)
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration)
|
||||
void bdrv_dirty_bitmap_skip_store(BdrvDirtyBitmap *bitmap, bool skip)
|
||||
{
|
||||
qemu_mutex_lock(bitmap->mutex);
|
||||
bitmap->migration = migration;
|
||||
bitmap->skip_store = skip;
|
||||
qemu_mutex_unlock(bitmap->mutex);
|
||||
}
|
||||
|
||||
bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
return bitmap->persistent && !bitmap->migration;
|
||||
return bitmap->persistent && !bitmap->skip_store;
|
||||
}
|
||||
|
||||
bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap)
|
||||
@@ -778,7 +782,7 @@ bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs)
|
||||
{
|
||||
BdrvDirtyBitmap *bm;
|
||||
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
|
||||
if (bm->persistent && !bm->readonly && !bm->migration) {
|
||||
if (bm->persistent && !bm->readonly && !bm->skip_store) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -810,6 +814,12 @@ bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap,
|
||||
return hbitmap_next_dirty_area(bitmap->bitmap, offset, bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* bdrv_merge_dirty_bitmap: merge src into dest.
|
||||
* Ensures permissions on bitmaps are reasonable; use for public API.
|
||||
*
|
||||
* @backup: If provided, make a copy of dest here prior to merge.
|
||||
*/
|
||||
void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
|
||||
HBitmap **backup, Error **errp)
|
||||
{
|
||||
@@ -833,13 +843,7 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (backup) {
|
||||
*backup = dest->bitmap;
|
||||
dest->bitmap = hbitmap_alloc(dest->size, hbitmap_granularity(*backup));
|
||||
ret = hbitmap_merge(*backup, src->bitmap, dest->bitmap);
|
||||
} else {
|
||||
ret = hbitmap_merge(dest->bitmap, src->bitmap, dest->bitmap);
|
||||
}
|
||||
ret = bdrv_dirty_bitmap_merge_internal(dest, src, backup, false);
|
||||
assert(ret);
|
||||
|
||||
out:
|
||||
@@ -848,3 +852,47 @@ out:
|
||||
qemu_mutex_unlock(src->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bdrv_dirty_bitmap_merge_internal: merge src into dest.
|
||||
* Does NOT check bitmap permissions; not suitable for use as public API.
|
||||
*
|
||||
* @backup: If provided, make a copy of dest here prior to merge.
|
||||
* @lock: If true, lock and unlock bitmaps on the way in/out.
|
||||
* returns true if the merge succeeded; false if unattempted.
|
||||
*/
|
||||
bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
|
||||
const BdrvDirtyBitmap *src,
|
||||
HBitmap **backup,
|
||||
bool lock)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
assert(!bdrv_dirty_bitmap_readonly(dest));
|
||||
assert(!bdrv_dirty_bitmap_inconsistent(dest));
|
||||
assert(!bdrv_dirty_bitmap_inconsistent(src));
|
||||
|
||||
if (lock) {
|
||||
qemu_mutex_lock(dest->mutex);
|
||||
if (src->mutex != dest->mutex) {
|
||||
qemu_mutex_lock(src->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
if (backup) {
|
||||
*backup = dest->bitmap;
|
||||
dest->bitmap = hbitmap_alloc(dest->size, hbitmap_granularity(*backup));
|
||||
ret = hbitmap_merge(*backup, src->bitmap, dest->bitmap);
|
||||
} else {
|
||||
ret = hbitmap_merge(dest->bitmap, src->bitmap, dest->bitmap);
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
qemu_mutex_unlock(dest->mutex);
|
||||
if (src->mutex != dest->mutex) {
|
||||
qemu_mutex_unlock(src->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+5
-3
@@ -476,7 +476,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
int64_t next_offset = offset + nb_chunks * s->granularity;
|
||||
int64_t next_chunk = next_offset / s->granularity;
|
||||
if (next_offset >= s->bdev_length ||
|
||||
!bdrv_get_dirty_locked(source, s->dirty_bitmap, next_offset)) {
|
||||
!bdrv_dirty_bitmap_get_locked(s->dirty_bitmap, next_offset)) {
|
||||
break;
|
||||
}
|
||||
if (test_bit(next_chunk, s->in_flight_bitmap)) {
|
||||
@@ -1755,8 +1755,10 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
|
||||
bool is_none_mode;
|
||||
BlockDriverState *base;
|
||||
|
||||
if (mode == MIRROR_SYNC_MODE_INCREMENTAL) {
|
||||
error_setg(errp, "Sync mode 'incremental' not supported");
|
||||
if ((mode == MIRROR_SYNC_MODE_INCREMENTAL) ||
|
||||
(mode == MIRROR_SYNC_MODE_BITMAP)) {
|
||||
error_setg(errp, "Sync mode '%s' not supported",
|
||||
MirrorSyncMode_str(mode));
|
||||
return;
|
||||
}
|
||||
is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
|
||||
|
||||
@@ -79,6 +79,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
|
||||
info->backing_file = g_strdup(bs->backing_file);
|
||||
}
|
||||
|
||||
if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
|
||||
info->has_dirty_bitmaps = true;
|
||||
info->dirty_bitmaps = bdrv_query_dirty_bitmaps(bs);
|
||||
}
|
||||
|
||||
info->detect_zeroes = bs->detect_zeroes;
|
||||
|
||||
if (blk && blk_get_public(blk)->throttle_group_member.throttle_state) {
|
||||
|
||||
+1
-1
@@ -543,7 +543,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
|
||||
s->backup_job = backup_job_create(
|
||||
NULL, s->secondary_disk->bs, s->hidden_disk->bs,
|
||||
0, MIRROR_SYNC_MODE_NONE, NULL, false,
|
||||
0, MIRROR_SYNC_MODE_NONE, NULL, 0, false,
|
||||
BLOCKDEV_ON_ERROR_REPORT,
|
||||
BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL,
|
||||
backup_job_completed, bs, NULL, &local_err);
|
||||
|
||||
@@ -41,6 +41,7 @@ mirror_yield_in_flight(void *s, int64_t offset, int in_flight) "s %p offset %" P
|
||||
backup_do_cow_enter(void *job, int64_t start, int64_t offset, uint64_t bytes) "job %p start %" PRId64 " offset %" PRId64 " bytes %" PRIu64
|
||||
backup_do_cow_return(void *job, int64_t offset, uint64_t bytes, int ret) "job %p offset %" PRId64 " bytes %" PRIu64 " ret %d"
|
||||
backup_do_cow_skip(void *job, int64_t start) "job %p start %"PRId64
|
||||
backup_do_cow_skip_range(void *job, int64_t start, uint64_t bytes) "job %p start %"PRId64" bytes %"PRId64
|
||||
backup_do_cow_process(void *job, int64_t start) "job %p start %"PRId64
|
||||
backup_do_cow_read_fail(void *job, int64_t start, int ret) "job %p start %"PRId64" ret %d"
|
||||
backup_do_cow_write_fail(void *job, int64_t start, int ret) "job %p start %"PRId64" ret %d"
|
||||
|
||||
+222
-147
@@ -2136,6 +2136,51 @@ static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
|
||||
errp);
|
||||
}
|
||||
|
||||
static BdrvDirtyBitmap *do_block_dirty_bitmap_remove(
|
||||
const char *node, const char *name, bool release,
|
||||
BlockDriverState **bitmap_bs, Error **errp);
|
||||
|
||||
static void block_dirty_bitmap_remove_prepare(BlkActionState *common,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDirtyBitmap *action;
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
if (action_check_completion_mode(common, errp) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
action = common->action->u.block_dirty_bitmap_remove.data;
|
||||
|
||||
state->bitmap = do_block_dirty_bitmap_remove(action->node, action->name,
|
||||
false, &state->bs, errp);
|
||||
if (state->bitmap) {
|
||||
bdrv_dirty_bitmap_skip_store(state->bitmap, true);
|
||||
bdrv_dirty_bitmap_set_busy(state->bitmap, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_remove_abort(BlkActionState *common)
|
||||
{
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
if (state->bitmap) {
|
||||
bdrv_dirty_bitmap_skip_store(state->bitmap, false);
|
||||
bdrv_dirty_bitmap_set_busy(state->bitmap, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_remove_commit(BlkActionState *common)
|
||||
{
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
bdrv_dirty_bitmap_set_busy(state->bitmap, false);
|
||||
bdrv_release_dirty_bitmap(state->bs, state->bitmap);
|
||||
}
|
||||
|
||||
static void abort_prepare(BlkActionState *common, Error **errp)
|
||||
{
|
||||
error_setg(errp, "Transaction aborted using Abort action");
|
||||
@@ -2213,6 +2258,12 @@ static const BlkActionOps actions[] = {
|
||||
.commit = block_dirty_bitmap_free_backup,
|
||||
.abort = block_dirty_bitmap_restore,
|
||||
},
|
||||
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_REMOVE] = {
|
||||
.instance_size = sizeof(BlockDirtyBitmapState),
|
||||
.prepare = block_dirty_bitmap_remove_prepare,
|
||||
.commit = block_dirty_bitmap_remove_commit,
|
||||
.abort = block_dirty_bitmap_remove_abort,
|
||||
},
|
||||
/* Where are transactions for MIRROR, COMMIT and STREAM?
|
||||
* Although these blockjobs use transaction callbacks like the backup job,
|
||||
* these jobs do not necessarily adhere to transaction semantics.
|
||||
@@ -2813,7 +2864,6 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
AioContext *aio_context = NULL;
|
||||
|
||||
if (!name || name[0] == '\0') {
|
||||
error_setg(errp, "Bitmap name cannot be empty");
|
||||
@@ -2849,16 +2899,20 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
}
|
||||
|
||||
if (persistent) {
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
bool ok;
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
if (!bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) {
|
||||
goto out;
|
||||
ok = bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp);
|
||||
aio_context_release(aio_context);
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
|
||||
if (bitmap == NULL) {
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (disabled) {
|
||||
@@ -2866,45 +2920,54 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
}
|
||||
|
||||
bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
|
||||
out:
|
||||
if (aio_context) {
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static BdrvDirtyBitmap *do_block_dirty_bitmap_remove(
|
||||
const char *node, const char *name, bool release,
|
||||
BlockDriverState **bitmap_bs, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
|
||||
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
||||
if (!bitmap || !bs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
|
||||
errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
Error *local_err = NULL;
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err);
|
||||
aio_context_release(aio_context);
|
||||
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (release) {
|
||||
bdrv_release_dirty_bitmap(bs, bitmap);
|
||||
}
|
||||
|
||||
if (bitmap_bs) {
|
||||
*bitmap_bs = bs;
|
||||
}
|
||||
|
||||
return release ? NULL : bitmap;
|
||||
}
|
||||
|
||||
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
Error *local_err = NULL;
|
||||
AioContext *aio_context = NULL;
|
||||
|
||||
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
||||
if (!bitmap || !bs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
|
||||
errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_release_dirty_bitmap(bs, bitmap);
|
||||
out:
|
||||
if (aio_context) {
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
do_block_dirty_bitmap_remove(node, name, true, NULL, errp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3427,20 +3490,16 @@ out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
|
||||
Error **errp)
|
||||
/* Common QMP interface for drive-backup and blockdev-backup */
|
||||
static BlockJob *do_backup_common(BackupCommon *backup,
|
||||
BlockDriverState *bs,
|
||||
BlockDriverState *target_bs,
|
||||
AioContext *aio_context,
|
||||
JobTxn *txn, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *target_bs;
|
||||
BlockDriverState *source = NULL;
|
||||
BlockJob *job = NULL;
|
||||
BdrvDirtyBitmap *bmap = NULL;
|
||||
AioContext *aio_context;
|
||||
QDict *options = NULL;
|
||||
Error *local_err = NULL;
|
||||
int flags, job_flags = JOB_DEFAULT;
|
||||
int64_t size;
|
||||
bool set_backing_hd = false;
|
||||
int job_flags = JOB_DEFAULT;
|
||||
int ret;
|
||||
|
||||
if (!backup->has_speed) {
|
||||
@@ -3452,9 +3511,6 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
|
||||
if (!backup->has_on_target_error) {
|
||||
backup->on_target_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
}
|
||||
if (!backup->has_mode) {
|
||||
backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||
}
|
||||
if (!backup->has_job_id) {
|
||||
backup->job_id = NULL;
|
||||
}
|
||||
@@ -3468,6 +3524,107 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
|
||||
backup->compress = false;
|
||||
}
|
||||
|
||||
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
|
||||
(backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
|
||||
/* done before desugaring 'incremental' to print the right message */
|
||||
if (!backup->has_bitmap) {
|
||||
error_setg(errp, "must provide a valid bitmap name for "
|
||||
"'%s' sync mode", MirrorSyncMode_str(backup->sync));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL) {
|
||||
if (backup->has_bitmap_mode &&
|
||||
backup->bitmap_mode != BITMAP_SYNC_MODE_ON_SUCCESS) {
|
||||
error_setg(errp, "Bitmap sync mode must be '%s' "
|
||||
"when using sync mode '%s'",
|
||||
BitmapSyncMode_str(BITMAP_SYNC_MODE_ON_SUCCESS),
|
||||
MirrorSyncMode_str(backup->sync));
|
||||
return NULL;
|
||||
}
|
||||
backup->has_bitmap_mode = true;
|
||||
backup->sync = MIRROR_SYNC_MODE_BITMAP;
|
||||
backup->bitmap_mode = BITMAP_SYNC_MODE_ON_SUCCESS;
|
||||
}
|
||||
|
||||
if (backup->has_bitmap) {
|
||||
bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap);
|
||||
if (!bmap) {
|
||||
error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap);
|
||||
return NULL;
|
||||
}
|
||||
if (!backup->has_bitmap_mode) {
|
||||
error_setg(errp, "Bitmap sync mode must be given "
|
||||
"when providing a bitmap");
|
||||
return NULL;
|
||||
}
|
||||
if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_ALLOW_RO, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This does not produce a useful bitmap artifact: */
|
||||
if (backup->sync == MIRROR_SYNC_MODE_NONE) {
|
||||
error_setg(errp, "sync mode '%s' does not produce meaningful bitmap"
|
||||
" outputs", MirrorSyncMode_str(backup->sync));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If the bitmap isn't used for input or output, this is useless: */
|
||||
if (backup->bitmap_mode == BITMAP_SYNC_MODE_NEVER &&
|
||||
backup->sync != MIRROR_SYNC_MODE_BITMAP) {
|
||||
error_setg(errp, "Bitmap sync mode '%s' has no meaningful effect"
|
||||
" when combined with sync mode '%s'",
|
||||
BitmapSyncMode_str(backup->bitmap_mode),
|
||||
MirrorSyncMode_str(backup->sync));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!backup->has_bitmap && backup->has_bitmap_mode) {
|
||||
error_setg(errp, "Cannot specify bitmap sync mode without a bitmap");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!backup->auto_finalize) {
|
||||
job_flags |= JOB_MANUAL_FINALIZE;
|
||||
}
|
||||
if (!backup->auto_dismiss) {
|
||||
job_flags |= JOB_MANUAL_DISMISS;
|
||||
}
|
||||
|
||||
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
|
||||
backup->sync, bmap, backup->bitmap_mode,
|
||||
backup->compress,
|
||||
backup->on_source_error,
|
||||
backup->on_target_error,
|
||||
job_flags, NULL, NULL, txn, errp);
|
||||
return job;
|
||||
}
|
||||
|
||||
static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *target_bs;
|
||||
BlockDriverState *source = NULL;
|
||||
BlockJob *job = NULL;
|
||||
AioContext *aio_context;
|
||||
QDict *options;
|
||||
Error *local_err = NULL;
|
||||
int flags;
|
||||
int64_t size;
|
||||
bool set_backing_hd = false;
|
||||
|
||||
if (!backup->has_mode) {
|
||||
backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||
}
|
||||
|
||||
bs = bdrv_lookup_bs(backup->device, backup->device, errp);
|
||||
if (!bs) {
|
||||
return NULL;
|
||||
@@ -3531,10 +3688,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
|
||||
goto out;
|
||||
}
|
||||
|
||||
options = qdict_new();
|
||||
qdict_put_str(options, "discard", "unmap");
|
||||
qdict_put_str(options, "detect-zeroes", "unmap");
|
||||
if (backup->format) {
|
||||
if (!options) {
|
||||
options = qdict_new();
|
||||
}
|
||||
qdict_put_str(options, "driver", backup->format);
|
||||
}
|
||||
|
||||
@@ -3543,12 +3700,6 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(target_bs);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (set_backing_hd) {
|
||||
bdrv_set_backing_hd(target_bs, source, &local_err);
|
||||
if (local_err) {
|
||||
@@ -3556,31 +3707,8 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
|
||||
}
|
||||
}
|
||||
|
||||
if (backup->has_bitmap) {
|
||||
bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap);
|
||||
if (!bmap) {
|
||||
error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap);
|
||||
goto unref;
|
||||
}
|
||||
if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
|
||||
goto unref;
|
||||
}
|
||||
}
|
||||
if (!backup->auto_finalize) {
|
||||
job_flags |= JOB_MANUAL_FINALIZE;
|
||||
}
|
||||
if (!backup->auto_dismiss) {
|
||||
job_flags |= JOB_MANUAL_DISMISS;
|
||||
}
|
||||
|
||||
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
|
||||
backup->sync, bmap, backup->compress,
|
||||
backup->on_source_error, backup->on_target_error,
|
||||
job_flags, NULL, NULL, txn, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
goto unref;
|
||||
}
|
||||
job = do_backup_common(qapi_DriveBackup_base(backup),
|
||||
bs, target_bs, aio_context, txn, errp);
|
||||
|
||||
unref:
|
||||
bdrv_unref(target_bs);
|
||||
@@ -3614,78 +3742,25 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *target_bs;
|
||||
Error *local_err = NULL;
|
||||
BdrvDirtyBitmap *bmap = NULL;
|
||||
AioContext *aio_context;
|
||||
BlockJob *job = NULL;
|
||||
int job_flags = JOB_DEFAULT;
|
||||
int ret;
|
||||
|
||||
if (!backup->has_speed) {
|
||||
backup->speed = 0;
|
||||
}
|
||||
if (!backup->has_on_source_error) {
|
||||
backup->on_source_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
}
|
||||
if (!backup->has_on_target_error) {
|
||||
backup->on_target_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
}
|
||||
if (!backup->has_job_id) {
|
||||
backup->job_id = NULL;
|
||||
}
|
||||
if (!backup->has_auto_finalize) {
|
||||
backup->auto_finalize = true;
|
||||
}
|
||||
if (!backup->has_auto_dismiss) {
|
||||
backup->auto_dismiss = true;
|
||||
}
|
||||
if (!backup->has_compress) {
|
||||
backup->compress = false;
|
||||
}
|
||||
BlockJob *job;
|
||||
|
||||
bs = bdrv_lookup_bs(backup->device, backup->device, errp);
|
||||
if (!bs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
|
||||
if (!target_bs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
|
||||
if (!target_bs) {
|
||||
goto out;
|
||||
}
|
||||
job = do_backup_common(qapi_BlockdevBackup_base(backup),
|
||||
bs, target_bs, aio_context, txn, errp);
|
||||
|
||||
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (backup->has_bitmap) {
|
||||
bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap);
|
||||
if (!bmap) {
|
||||
error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap);
|
||||
goto out;
|
||||
}
|
||||
if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!backup->auto_finalize) {
|
||||
job_flags |= JOB_MANUAL_FINALIZE;
|
||||
}
|
||||
if (!backup->auto_dismiss) {
|
||||
job_flags |= JOB_MANUAL_DISMISS;
|
||||
}
|
||||
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
|
||||
backup->sync, bmap, backup->compress,
|
||||
backup->on_source_error, backup->on_target_error,
|
||||
job_flags, NULL, NULL, txn, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
return job;
|
||||
}
|
||||
|
||||
@@ -1147,7 +1147,8 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
|
||||
* @target: Block device to write to.
|
||||
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
|
||||
* @sync_mode: What parts of the disk image should be copied to the destination.
|
||||
* @sync_bitmap: The dirty bitmap if sync_mode is MIRROR_SYNC_MODE_INCREMENTAL.
|
||||
* @sync_bitmap: The dirty bitmap if sync_mode is 'bitmap' or 'incremental'
|
||||
* @bitmap_mode: The bitmap synchronization policy to use.
|
||||
* @on_source_error: The action to take upon error reading from the source.
|
||||
* @on_target_error: The action to take upon error writing to the target.
|
||||
* @creation_flags: Flags that control the behavior of the Job lifetime.
|
||||
@@ -1163,6 +1164,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *target, int64_t speed,
|
||||
MirrorSyncMode sync_mode,
|
||||
BdrvDirtyBitmap *sync_bitmap,
|
||||
BitmapSyncMode bitmap_mode,
|
||||
bool compress,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
@@ -1251,6 +1253,9 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
|
||||
|
||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
|
||||
void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup);
|
||||
bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
|
||||
const BdrvDirtyBitmap *src,
|
||||
HBitmap **backup, bool lock);
|
||||
|
||||
void bdrv_inc_in_flight(BlockDriverState *bs);
|
||||
void bdrv_dec_in_flight(BlockDriverState *bs);
|
||||
|
||||
@@ -83,13 +83,13 @@ void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap);
|
||||
void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy);
|
||||
void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
|
||||
HBitmap **backup, Error **errp);
|
||||
void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration);
|
||||
void bdrv_dirty_bitmap_skip_store(BdrvDirtyBitmap *bitmap, bool skip);
|
||||
bool bdrv_dirty_bitmap_get(BdrvDirtyBitmap *bitmap, int64_t offset);
|
||||
|
||||
/* Functions that require manual locking. */
|
||||
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
|
||||
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
|
||||
bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t offset);
|
||||
bool bdrv_dirty_bitmap_get_locked(BdrvDirtyBitmap *bitmap, int64_t offset);
|
||||
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
||||
int64_t offset, int64_t bytes);
|
||||
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
||||
|
||||
@@ -326,7 +326,7 @@ static int init_dirty_bitmap_migration(void)
|
||||
|
||||
/* unset migration flags here, to not roll back it */
|
||||
QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) {
|
||||
bdrv_dirty_bitmap_set_migration(dbms->bitmap, true);
|
||||
bdrv_dirty_bitmap_skip_store(dbms->bitmap, true);
|
||||
}
|
||||
|
||||
if (QSIMPLEQ_EMPTY(&dirty_bitmap_mig_state.dbms_list)) {
|
||||
|
||||
+2
-3
@@ -521,7 +521,6 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
|
||||
int is_async)
|
||||
{
|
||||
BlkMigBlock *blk;
|
||||
BlockDriverState *bs = blk_bs(bmds->blk);
|
||||
int64_t total_sectors = bmds->total_sectors;
|
||||
int64_t sector;
|
||||
int nr_sectors;
|
||||
@@ -536,8 +535,8 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
|
||||
blk_mig_unlock();
|
||||
}
|
||||
bdrv_dirty_bitmap_lock(bmds->dirty_bitmap);
|
||||
if (bdrv_get_dirty_locked(bs, bmds->dirty_bitmap,
|
||||
sector * BDRV_SECTOR_SIZE)) {
|
||||
if (bdrv_dirty_bitmap_get_locked(bmds->dirty_bitmap,
|
||||
sector * BDRV_SECTOR_SIZE)) {
|
||||
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
|
||||
nr_sectors = total_sectors - sector;
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -2004,7 +2004,7 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset,
|
||||
bdrv_dirty_bitmap_lock(bitmap);
|
||||
|
||||
it = bdrv_dirty_iter_new(bitmap);
|
||||
dirty = bdrv_get_dirty_locked(NULL, bitmap, offset);
|
||||
dirty = bdrv_dirty_bitmap_get_locked(bitmap, offset);
|
||||
|
||||
assert(begin < overall_end && nb_extents);
|
||||
while (begin < overall_end && i < nb_extents) {
|
||||
|
||||
+97
-99
@@ -360,6 +360,9 @@
|
||||
# @write_threshold: configured write threshold for the device.
|
||||
# 0 if disabled. (Since 2.3)
|
||||
#
|
||||
# @dirty-bitmaps: dirty bitmaps information (only present if node
|
||||
# has one or more dirty bitmaps) (Since 4.2)
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
##
|
||||
@@ -378,7 +381,7 @@
|
||||
'*bps_wr_max_length': 'int', '*iops_max_length': 'int',
|
||||
'*iops_rd_max_length': 'int', '*iops_wr_max_length': 'int',
|
||||
'*iops_size': 'int', '*group': 'str', 'cache': 'BlockdevCacheInfo',
|
||||
'write_threshold': 'int' } }
|
||||
'write_threshold': 'int', '*dirty-bitmaps': ['BlockDirtyInfo'] } }
|
||||
|
||||
##
|
||||
# @BlockDeviceIoStatus:
|
||||
@@ -656,6 +659,7 @@
|
||||
#
|
||||
# @dirty-bitmaps: dirty bitmaps information (only present if the
|
||||
# driver has one or more dirty bitmaps) (Since 2.0)
|
||||
# Deprecated in 4.2; see BlockDeviceInfo instead.
|
||||
#
|
||||
# @io-status: @BlockDeviceIoStatus. Only present if the device
|
||||
# supports it and the VM is configured to stop on errors
|
||||
@@ -1127,12 +1131,35 @@
|
||||
#
|
||||
# @none: only copy data written from now on
|
||||
#
|
||||
# @incremental: only copy data described by the dirty bitmap. Since: 2.4
|
||||
# @incremental: only copy data described by the dirty bitmap. (since: 2.4)
|
||||
#
|
||||
# @bitmap: only copy data described by the dirty bitmap. (since: 4.2)
|
||||
# Behavior on completion is determined by the BitmapSyncMode.
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
{ 'enum': 'MirrorSyncMode',
|
||||
'data': ['top', 'full', 'none', 'incremental'] }
|
||||
'data': ['top', 'full', 'none', 'incremental', 'bitmap'] }
|
||||
|
||||
##
|
||||
# @BitmapSyncMode:
|
||||
#
|
||||
# An enumeration of possible behaviors for the synchronization of a bitmap
|
||||
# when used for data copy operations.
|
||||
#
|
||||
# @on-success: The bitmap is only synced when the operation is successful.
|
||||
# This is the behavior always used for 'INCREMENTAL' backups.
|
||||
#
|
||||
# @never: The bitmap is never synchronized with the operation, and is
|
||||
# treated solely as a read-only manifest of blocks to copy.
|
||||
#
|
||||
# @always: The bitmap is always synchronized with the operation,
|
||||
# regardless of whether or not the operation was successful.
|
||||
#
|
||||
# Since: 4.2
|
||||
##
|
||||
{ 'enum': 'BitmapSyncMode',
|
||||
'data': ['on-success', 'never', 'always'] }
|
||||
|
||||
##
|
||||
# @MirrorCopyMode:
|
||||
@@ -1315,13 +1342,73 @@
|
||||
'data': { 'node': 'str', 'overlay': 'str' } }
|
||||
|
||||
##
|
||||
# @DriveBackup:
|
||||
# @BackupCommon:
|
||||
#
|
||||
# @job-id: identifier for the newly-created block job. If
|
||||
# omitted, the device name will be used. (Since 2.7)
|
||||
#
|
||||
# @device: the device name or node-name of a root node which should be copied.
|
||||
#
|
||||
# @sync: what parts of the disk image should be copied to the destination
|
||||
# (all the disk, only the sectors allocated in the topmost image, from a
|
||||
# dirty bitmap, or only new I/O).
|
||||
#
|
||||
# @speed: the maximum speed, in bytes per second. The default is 0,
|
||||
# for unlimited.
|
||||
#
|
||||
# @bitmap: The name of a dirty bitmap to use.
|
||||
# Must be present if sync is "bitmap" or "incremental".
|
||||
# Can be present if sync is "full" or "top".
|
||||
# Must not be present otherwise.
|
||||
# (Since 2.4 (drive-backup), 3.1 (blockdev-backup))
|
||||
#
|
||||
# @bitmap-mode: Specifies the type of data the bitmap should contain after
|
||||
# the operation concludes.
|
||||
# Must be present if a bitmap was provided,
|
||||
# Must NOT be present otherwise. (Since 4.2)
|
||||
#
|
||||
# @compress: true to compress data, if the target format supports it.
|
||||
# (default: false) (since 2.8)
|
||||
#
|
||||
# @on-source-error: the action to take on an error on the source,
|
||||
# default 'report'. 'stop' and 'enospc' can only be used
|
||||
# if the block device supports io-status (see BlockInfo).
|
||||
#
|
||||
# @on-target-error: the action to take on an error on the target,
|
||||
# default 'report' (no limitations, since this applies to
|
||||
# a different block device than @device).
|
||||
#
|
||||
# @auto-finalize: When false, this job will wait in a PENDING state after it has
|
||||
# finished its work, waiting for @block-job-finalize before
|
||||
# making any block graph changes.
|
||||
# When true, this job will automatically
|
||||
# perform its abort or commit actions.
|
||||
# Defaults to true. (Since 2.12)
|
||||
#
|
||||
# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it
|
||||
# has completely ceased all work, and awaits @block-job-dismiss.
|
||||
# When true, this job will automatically disappear from the query
|
||||
# list without user intervention.
|
||||
# Defaults to true. (Since 2.12)
|
||||
#
|
||||
# Note: @on-source-error and @on-target-error only affect background
|
||||
# I/O. If an error occurs during a guest write request, the device's
|
||||
# rerror/werror actions will be used.
|
||||
#
|
||||
# Since: 4.2
|
||||
##
|
||||
{ 'struct': 'BackupCommon',
|
||||
'data': { '*job-id': 'str', 'device': 'str',
|
||||
'sync': 'MirrorSyncMode', '*speed': 'int',
|
||||
'*bitmap': 'str', '*bitmap-mode': 'BitmapSyncMode',
|
||||
'*compress': 'bool',
|
||||
'*on-source-error': 'BlockdevOnError',
|
||||
'*on-target-error': 'BlockdevOnError',
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
||||
|
||||
##
|
||||
# @DriveBackup:
|
||||
#
|
||||
# @target: the target of the new image. If the file exists, or if it
|
||||
# is a device, the existing file/device will be used as the new
|
||||
# destination. If it does not exist, a new file will be created.
|
||||
@@ -1329,116 +1416,27 @@
|
||||
# @format: the format of the new destination, default is to
|
||||
# probe if @mode is 'existing', else the format of the source
|
||||
#
|
||||
# @sync: what parts of the disk image should be copied to the destination
|
||||
# (all the disk, only the sectors allocated in the topmost image, from a
|
||||
# dirty bitmap, or only new I/O).
|
||||
#
|
||||
# @mode: whether and how QEMU should create a new image, default is
|
||||
# 'absolute-paths'.
|
||||
#
|
||||
# @speed: the maximum speed, in bytes per second
|
||||
#
|
||||
# @bitmap: the name of dirty bitmap if sync is "incremental".
|
||||
# Must be present if sync is "incremental", must NOT be present
|
||||
# otherwise. (Since 2.4)
|
||||
#
|
||||
# @compress: true to compress data, if the target format supports it.
|
||||
# (default: false) (since 2.8)
|
||||
#
|
||||
# @on-source-error: the action to take on an error on the source,
|
||||
# default 'report'. 'stop' and 'enospc' can only be used
|
||||
# if the block device supports io-status (see BlockInfo).
|
||||
#
|
||||
# @on-target-error: the action to take on an error on the target,
|
||||
# default 'report' (no limitations, since this applies to
|
||||
# a different block device than @device).
|
||||
#
|
||||
# @auto-finalize: When false, this job will wait in a PENDING state after it has
|
||||
# finished its work, waiting for @block-job-finalize before
|
||||
# making any block graph changes.
|
||||
# When true, this job will automatically
|
||||
# perform its abort or commit actions.
|
||||
# Defaults to true. (Since 2.12)
|
||||
#
|
||||
# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it
|
||||
# has completely ceased all work, and awaits @block-job-dismiss.
|
||||
# When true, this job will automatically disappear from the query
|
||||
# list without user intervention.
|
||||
# Defaults to true. (Since 2.12)
|
||||
#
|
||||
# Note: @on-source-error and @on-target-error only affect background
|
||||
# I/O. If an error occurs during a guest write request, the device's
|
||||
# rerror/werror actions will be used.
|
||||
#
|
||||
# Since: 1.6
|
||||
##
|
||||
{ 'struct': 'DriveBackup',
|
||||
'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
|
||||
'*format': 'str', 'sync': 'MirrorSyncMode',
|
||||
'*mode': 'NewImageMode', '*speed': 'int',
|
||||
'*bitmap': 'str', '*compress': 'bool',
|
||||
'*on-source-error': 'BlockdevOnError',
|
||||
'*on-target-error': 'BlockdevOnError',
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
||||
'base': 'BackupCommon',
|
||||
'data': { 'target': 'str',
|
||||
'*format': 'str',
|
||||
'*mode': 'NewImageMode' } }
|
||||
|
||||
##
|
||||
# @BlockdevBackup:
|
||||
#
|
||||
# @job-id: identifier for the newly-created block job. If
|
||||
# omitted, the device name will be used. (Since 2.7)
|
||||
#
|
||||
# @device: the device name or node-name of a root node which should be copied.
|
||||
#
|
||||
# @target: the device name or node-name of the backup target node.
|
||||
#
|
||||
# @sync: what parts of the disk image should be copied to the destination
|
||||
# (all the disk, only the sectors allocated in the topmost image, or
|
||||
# only new I/O).
|
||||
#
|
||||
# @speed: the maximum speed, in bytes per second. The default is 0,
|
||||
# for unlimited.
|
||||
#
|
||||
# @bitmap: the name of dirty bitmap if sync is "incremental".
|
||||
# Must be present if sync is "incremental", must NOT be present
|
||||
# otherwise. (Since 3.1)
|
||||
#
|
||||
# @compress: true to compress data, if the target format supports it.
|
||||
# (default: false) (since 2.8)
|
||||
#
|
||||
# @on-source-error: the action to take on an error on the source,
|
||||
# default 'report'. 'stop' and 'enospc' can only be used
|
||||
# if the block device supports io-status (see BlockInfo).
|
||||
#
|
||||
# @on-target-error: the action to take on an error on the target,
|
||||
# default 'report' (no limitations, since this applies to
|
||||
# a different block device than @device).
|
||||
#
|
||||
# @auto-finalize: When false, this job will wait in a PENDING state after it has
|
||||
# finished its work, waiting for @block-job-finalize before
|
||||
# making any block graph changes.
|
||||
# When true, this job will automatically
|
||||
# perform its abort or commit actions.
|
||||
# Defaults to true. (Since 2.12)
|
||||
#
|
||||
# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it
|
||||
# has completely ceased all work, and awaits @block-job-dismiss.
|
||||
# When true, this job will automatically disappear from the query
|
||||
# list without user intervention.
|
||||
# Defaults to true. (Since 2.12)
|
||||
#
|
||||
# Note: @on-source-error and @on-target-error only affect background
|
||||
# I/O. If an error occurs during a guest write request, the device's
|
||||
# rerror/werror actions will be used.
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
{ 'struct': 'BlockdevBackup',
|
||||
'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
|
||||
'sync': 'MirrorSyncMode', '*speed': 'int',
|
||||
'*bitmap': 'str', '*compress': 'bool',
|
||||
'*on-source-error': 'BlockdevOnError',
|
||||
'*on-target-error': 'BlockdevOnError',
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
||||
'base': 'BackupCommon',
|
||||
'data': { 'target': 'str' } }
|
||||
|
||||
##
|
||||
# @blockdev-snapshot-sync:
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#
|
||||
# - @abort: since 1.6
|
||||
# - @block-dirty-bitmap-add: since 2.5
|
||||
# - @block-dirty-bitmap-remove: since 4.2
|
||||
# - @block-dirty-bitmap-clear: since 2.5
|
||||
# - @block-dirty-bitmap-enable: since 4.0
|
||||
# - @block-dirty-bitmap-disable: since 4.0
|
||||
@@ -61,6 +62,7 @@
|
||||
'data': {
|
||||
'abort': 'Abort',
|
||||
'block-dirty-bitmap-add': 'BlockDirtyBitmapAdd',
|
||||
'block-dirty-bitmap-remove': 'BlockDirtyBitmap',
|
||||
'block-dirty-bitmap-clear': 'BlockDirtyBitmap',
|
||||
'block-dirty-bitmap-enable': 'BlockDirtyBitmap',
|
||||
'block-dirty-bitmap-disable': 'BlockDirtyBitmap',
|
||||
|
||||
@@ -154,6 +154,18 @@ The ``status'' field of the ``BlockDirtyInfo'' structure, returned by
|
||||
the query-block command is deprecated. Two new boolean fields,
|
||||
``recording'' and ``busy'' effectively replace it.
|
||||
|
||||
@subsection query-block result field dirty-bitmaps (Since 4.2)
|
||||
|
||||
The ``dirty-bitmaps`` field of the ``BlockInfo`` structure, returned by
|
||||
the query-block command is itself now deprecated. The ``dirty-bitmaps``
|
||||
field of the ``BlockDeviceInfo`` struct should be used instead, which is the
|
||||
type of the ``inserted`` field in query-block replies, as well as the
|
||||
type of array items in query-named-block-nodes.
|
||||
|
||||
Since the ``dirty-bitmaps`` field is optionally present in both the old and
|
||||
new locations, clients must use introspection to learn where to anticipate
|
||||
the field if/when it does appear in command output.
|
||||
|
||||
@subsection query-cpus (since 2.12.0)
|
||||
|
||||
The ``query-cpus'' command is replaced by the ``query-cpus-fast'' command.
|
||||
|
||||
@@ -85,11 +85,7 @@ class TestSingleDrive(ImageCommitTestCase):
|
||||
qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img)
|
||||
qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img)
|
||||
self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=mid,backing.backing.node-name=base", interface="none")
|
||||
if iotests.qemu_default_machine == 's390-ccw-virtio':
|
||||
self.vm.add_device("virtio-scsi-ccw")
|
||||
else:
|
||||
self.vm.add_device("virtio-scsi-pci")
|
||||
|
||||
self.vm.add_device(iotests.get_virtio_scsi_device())
|
||||
self.vm.add_device("scsi-hd,id=scsi0,drive=drive0")
|
||||
self.vm.launch()
|
||||
self.has_quit = False
|
||||
|
||||
@@ -367,10 +367,8 @@ class ThrottleTestGroupNames(iotests.QMPTestCase):
|
||||
class ThrottleTestRemovableMedia(iotests.QMPTestCase):
|
||||
def setUp(self):
|
||||
self.vm = iotests.VM()
|
||||
if iotests.qemu_default_machine == 's390-ccw-virtio':
|
||||
self.vm.add_device("virtio-scsi-ccw,id=virtio-scsi")
|
||||
else:
|
||||
self.vm.add_device("virtio-scsi-pci,id=virtio-scsi")
|
||||
self.vm.add_device("{},id=virtio-scsi".format(
|
||||
iotests.get_virtio_scsi_device()))
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
|
||||
@@ -35,11 +35,8 @@ class TestBlockdevDel(iotests.QMPTestCase):
|
||||
def setUp(self):
|
||||
iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M')
|
||||
self.vm = iotests.VM()
|
||||
if iotests.qemu_default_machine == 's390-ccw-virtio':
|
||||
self.vm.add_device("virtio-scsi-ccw,id=virtio-scsi")
|
||||
else:
|
||||
self.vm.add_device("virtio-scsi-pci,id=virtio-scsi")
|
||||
|
||||
self.vm.add_device("{},id=virtio-scsi".format(
|
||||
iotests.get_virtio_scsi_device()))
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
|
||||
@@ -23,10 +23,7 @@ import os
|
||||
import iotests
|
||||
from iotests import log
|
||||
|
||||
if iotests.qemu_default_machine == 's390-ccw-virtio':
|
||||
virtio_scsi_device = 'virtio-scsi-ccw'
|
||||
else:
|
||||
virtio_scsi_device = 'virtio-scsi-pci'
|
||||
virtio_scsi_device = iotests.get_virtio_scsi_device()
|
||||
|
||||
vm = iotests.VM()
|
||||
vm.launch()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user