X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=blockdev.c;h=8e029e9c01b3ad6823bef64cd37e1741d195bc00;hb=c6b3a2e0c4342d171b35970921bff709c007dd62;hp=95cdd5a5cb0326dfdd331b19caf53c49a947e70d;hpb=54d31236b906c8f03eb011717de7bc47000720c3;p=mirror_qemu.git diff --git a/blockdev.c b/blockdev.c index 95cdd5a5cb..8e029e9c01 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1088,11 +1088,11 @@ void hmp_commit(Monitor *mon, const QDict *qdict) blk = blk_by_name(device); if (!blk) { - monitor_printf(mon, "Device '%s' not found\n", device); + error_report("Device '%s' not found", device); return; } if (!blk_is_available(blk)) { - monitor_printf(mon, "Device '%s' has no medium\n", device); + error_report("Device '%s' has no medium", device); return; } @@ -1105,8 +1105,7 @@ void hmp_commit(Monitor *mon, const QDict *qdict) aio_context_release(aio_context); } if (ret < 0) { - monitor_printf(mon, "'commit' error for '%s': %s\n", device, - strerror(-ret)); + error_report("'commit' error for '%s': %s", device, strerror(-ret)); } } @@ -1966,7 +1965,6 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common, qmp_block_dirty_bitmap_add(action->node, action->name, action->has_granularity, action->granularity, action->has_persistent, action->persistent, - action->has_autoload, action->autoload, action->has_disabled, action->disabled, &local_err); @@ -2136,6 +2134,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->bitmap); +} + static void abort_prepare(BlkActionState *common, Error **errp) { error_setg(errp, "Transaction aborted using Abort action"); @@ -2213,6 +2256,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. @@ -2807,13 +2856,11 @@ out: void qmp_block_dirty_bitmap_add(const char *node, const char *name, bool has_granularity, uint32_t granularity, bool has_persistent, bool persistent, - bool has_autoload, bool autoload, bool has_disabled, bool disabled, Error **errp) { BlockDriverState *bs; BdrvDirtyBitmap *bitmap; - AioContext *aio_context = NULL; if (!name || name[0] == '\0') { error_setg(errp, "Bitmap name cannot be empty"); @@ -2840,25 +2887,19 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, persistent = false; } - if (has_autoload) { - warn_report("Autoload option is deprecated and its value is ignored"); - } - if (!has_disabled) { disabled = false; } - if (persistent) { - aio_context = bdrv_get_aio_context(bs); - aio_context_acquire(aio_context); - if (!bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) { - goto out; - } + if (persistent && + !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) + { + return; } bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); if (bitmap == NULL) { - goto out; + return; } if (disabled) { @@ -2866,45 +2907,46 @@ 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); - } } -void qmp_block_dirty_bitmap_remove(const char *node, const char *name, - Error **errp) +static BdrvDirtyBitmap *do_block_dirty_bitmap_remove( + const char *node, const char *name, bool release, + BlockDriverState **bitmap_bs, 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; + return NULL; } if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO, errp)) { - return; + return NULL; } - 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; - } + if (bdrv_dirty_bitmap_get_persistence(bitmap) && + bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0) + { + return NULL; } - bdrv_release_dirty_bitmap(bs, bitmap); - out: - if (aio_context) { - aio_context_release(aio_context); + if (release) { + bdrv_release_dirty_bitmap(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) +{ + do_block_dirty_bitmap_remove(node, name, true, NULL, errp); } /** @@ -3023,7 +3065,7 @@ static BdrvDirtyBitmap *do_block_dirty_bitmap_merge( bdrv_merge_dirty_bitmap(dst, anon, backup, errp); out: - bdrv_release_dirty_bitmap(bs, anon); + bdrv_release_dirty_bitmap(anon); return dst; } @@ -3162,7 +3204,7 @@ void qmp_block_resize(bool has_device, const char *device, } bdrv_drained_begin(bs); - ret = blk_truncate(blk, size, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp); bdrv_drained_end(bs); out: @@ -3427,20 +3469,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 +3490,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 +3503,108 @@ 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->filter_node_name, + 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 +3668,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 +3680,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 +3687,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 +3722,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; } - 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; + return NULL; } - ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); - if (ret < 0) { - goto out; - } + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); - 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; - } - } + job = do_backup_common(qapi_BlockdevBackup_base(backup), + bs, target_bs, aio_context, txn, errp); - 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; } @@ -3707,6 +3762,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, bool has_replaces, const char *replaces, enum MirrorSyncMode sync, BlockMirrorBackingMode backing_mode, + bool zero_target, bool has_speed, int64_t speed, bool has_granularity, uint32_t granularity, bool has_buf_size, int64_t buf_size, @@ -3815,7 +3871,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, */ mirror_start(job_id, bs, target, has_replaces ? replaces : NULL, job_flags, - speed, granularity, buf_size, sync, backing_mode, + speed, granularity, buf_size, sync, backing_mode, zero_target, on_source_error, on_target_error, unmap, filter_node_name, copy_mode, errp); } @@ -3831,6 +3887,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) int flags; int64_t size; const char *format = arg->format; + bool zero_target; int ret; bs = qmp_get_root_bs(arg->device, errp); @@ -3932,6 +3989,10 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) goto out; } + zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL && + (arg->mode == NEW_IMAGE_MODE_EXISTING || + !bdrv_has_zero_init(target_bs))); + ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); if (ret < 0) { bdrv_unref(target_bs); @@ -3940,7 +4001,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs, arg->has_replaces, arg->replaces, arg->sync, - backing_mode, arg->has_speed, arg->speed, + backing_mode, zero_target, + arg->has_speed, arg->speed, arg->has_granularity, arg->granularity, arg->has_buf_size, arg->buf_size, arg->has_on_source_error, arg->on_source_error, @@ -3980,6 +4042,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, AioContext *aio_context; BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN; Error *local_err = NULL; + bool zero_target; int ret; bs = qmp_get_root_bs(device, errp); @@ -3992,6 +4055,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, return; } + zero_target = (sync == MIRROR_SYNC_MODE_FULL); + aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); @@ -4002,7 +4067,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs, has_replaces, replaces, sync, backing_mode, - has_speed, speed, + zero_target, has_speed, speed, has_granularity, granularity, has_buf_size, buf_size, has_on_source_error, on_source_error,