X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/c5e4e49258e9b89cb34c085a419dd9f862935c48..1229e46d3cfe61ee0b11f08fbbc7530af1578637:/blockdev.c diff --git a/blockdev.c b/blockdev.c index a8755bd908..c30495d035 100644 --- a/blockdev.c +++ b/blockdev.c @@ -759,7 +759,8 @@ QemuOptsList qemu_legacy_drive_opts = { }, }; -DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) +DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, + Error **errp) { const char *value; BlockBackend *blk; @@ -808,7 +809,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) qemu_opt_rename(all_opts, opt_renames[i].from, opt_renames[i].to, &local_err); if (local_err) { - error_report_err(local_err); + error_propagate(errp, local_err); return NULL; } } @@ -819,7 +820,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) bool writethrough; if (bdrv_parse_cache_mode(value, &flags, &writethrough) != 0) { - error_report("invalid cache option"); + error_setg(errp, "invalid cache option"); return NULL; } @@ -847,7 +848,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) &error_abort); qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err); if (local_err) { - error_report_err(local_err); + error_propagate(errp, local_err); goto fail; } @@ -860,7 +861,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) media = MEDIA_CDROM; read_only = true; } else { - error_report("'%s' invalid media", value); + error_setg(errp, "'%s' invalid media", value); goto fail; } } @@ -885,7 +886,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) type++) { } if (type == IF_COUNT) { - error_report("unsupported bus type '%s'", value); + error_setg(errp, "unsupported bus type '%s'", value); goto fail; } } else { @@ -902,7 +903,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) if (index != -1) { if (bus_id != 0 || unit_id != -1) { - error_report("index cannot be used with bus and unit"); + error_setg(errp, "index cannot be used with bus and unit"); goto fail; } bus_id = drive_index_to_bus_id(type, index); @@ -921,13 +922,13 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) } if (max_devs && unit_id >= max_devs) { - error_report("unit %d too big (max is %d)", unit_id, max_devs - 1); + error_setg(errp, "unit %d too big (max is %d)", unit_id, max_devs - 1); goto fail; } if (drive_get(type, bus_id, unit_id) != NULL) { - error_report("drive with bus=%d, unit=%d (index=%d) exists", - bus_id, unit_id, index); + error_setg(errp, "drive with bus=%d, unit=%d (index=%d) exists", + bus_id, unit_id, index); goto fail; } @@ -970,7 +971,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) if (werror != NULL) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { - error_report("werror is not supported by this bus type"); + error_setg(errp, "werror is not supported by this bus type"); goto fail; } qdict_put_str(bs_opts, "werror", werror); @@ -980,7 +981,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) if (rerror != NULL) { if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) { - error_report("rerror is not supported by this bus type"); + error_setg(errp, "rerror is not supported by this bus type"); goto fail; } qdict_put_str(bs_opts, "rerror", rerror); @@ -991,7 +992,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) bs_opts = NULL; if (!blk) { if (local_err) { - error_report_err(local_err); + error_propagate(errp, local_err); } goto fail; } else { @@ -2009,14 +2010,8 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, return; } - if (bdrv_dirty_bitmap_frozen(state->bitmap)) { - error_setg(errp, "Cannot modify a frozen bitmap"); - return; - } else if (bdrv_dirty_bitmap_qmp_locked(state->bitmap)) { - error_setg(errp, "Cannot modify a locked bitmap"); - return; - } else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) { - error_setg(errp, "Cannot clear a disabled bitmap"); + if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { + error_setg(errp, "Cannot modify a bitmap in use by another operation"); return; } else if (bdrv_dirty_bitmap_readonly(state->bitmap)) { error_setg(errp, "Cannot clear a readonly bitmap"); @@ -2026,17 +2021,17 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, bdrv_clear_dirty_bitmap(state->bitmap, &state->backup); } -static void block_dirty_bitmap_clear_abort(BlkActionState *common) +static void block_dirty_bitmap_restore(BlkActionState *common) { BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, common, common); if (state->backup) { - bdrv_undo_clear_dirty_bitmap(state->bitmap, state->backup); + bdrv_restore_dirty_bitmap(state->bitmap, state->backup); } } -static void block_dirty_bitmap_clear_commit(BlkActionState *common) +static void block_dirty_bitmap_free_backup(BlkActionState *common) { BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, common, common); @@ -2064,6 +2059,13 @@ static void block_dirty_bitmap_enable_prepare(BlkActionState *common, return; } + if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be enabled", action->name); + return; + } + state->was_enabled = bdrv_dirty_bitmap_enabled(state->bitmap); bdrv_enable_dirty_bitmap(state->bitmap); } @@ -2098,6 +2100,13 @@ static void block_dirty_bitmap_disable_prepare(BlkActionState *common, return; } + if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be disabled", action->name); + return; + } + state->was_enabled = bdrv_dirty_bitmap_enabled(state->bitmap); bdrv_disable_dirty_bitmap(state->bitmap); } @@ -2112,6 +2121,35 @@ static void block_dirty_bitmap_disable_abort(BlkActionState *common) } } +static void block_dirty_bitmap_merge_prepare(BlkActionState *common, + Error **errp) +{ + BlockDirtyBitmapMerge *action; + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); + BdrvDirtyBitmap *merge_source; + + if (action_check_completion_mode(common, errp) < 0) { + return; + } + + action = common->action->u.x_block_dirty_bitmap_merge.data; + state->bitmap = block_dirty_bitmap_lookup(action->node, + action->dst_name, + &state->bs, + errp); + if (!state->bitmap) { + return; + } + + merge_source = bdrv_find_dirty_bitmap(state->bs, action->src_name); + if (!merge_source) { + return; + } + + bdrv_merge_dirty_bitmap(state->bitmap, merge_source, &state->backup, errp); +} + static void abort_prepare(BlkActionState *common, Error **errp) { error_setg(errp, "Transaction aborted using Abort action"); @@ -2170,8 +2208,8 @@ static const BlkActionOps actions[] = { [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, + .commit = block_dirty_bitmap_free_backup, + .abort = block_dirty_bitmap_restore, }, [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_ENABLE] = { .instance_size = sizeof(BlockDirtyBitmapState), @@ -2183,6 +2221,12 @@ static const BlkActionOps actions[] = { .prepare = block_dirty_bitmap_disable_prepare, .abort = block_dirty_bitmap_disable_abort, }, + [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_MERGE] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_merge_prepare, + .commit = block_dirty_bitmap_free_backup, + .abort = block_dirty_bitmap_restore, + }, /* 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. @@ -2847,15 +2891,10 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, return; } - if (bdrv_dirty_bitmap_frozen(bitmap)) { + if (bdrv_dirty_bitmap_user_locked(bitmap)) { error_setg(errp, - "Bitmap '%s' is currently frozen and cannot be removed", - name); - return; - } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) { - error_setg(errp, - "Bitmap '%s' is currently locked and cannot be removed", - name); + "Bitmap '%s' is currently in use by another operation and" + " cannot be removed", name); return; } @@ -2885,20 +2924,10 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, return; } - if (bdrv_dirty_bitmap_frozen(bitmap)) { - error_setg(errp, - "Bitmap '%s' is currently frozen and cannot be modified", - name); - return; - } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) { + if (bdrv_dirty_bitmap_user_locked(bitmap)) { error_setg(errp, - "Bitmap '%s' is currently locked and cannot be modified", - name); - return; - } else if (!bdrv_dirty_bitmap_enabled(bitmap)) { - error_setg(errp, - "Bitmap '%s' is currently disabled and cannot be cleared", - name); + "Bitmap '%s' is currently in use by another operation" + " and cannot be cleared", name); return; } else if (bdrv_dirty_bitmap_readonly(bitmap)) { error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name); @@ -2919,10 +2948,10 @@ void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name, return; } - if (bdrv_dirty_bitmap_frozen(bitmap)) { + if (bdrv_dirty_bitmap_user_locked(bitmap)) { error_setg(errp, - "Bitmap '%s' is currently frozen and cannot be enabled", - name); + "Bitmap '%s' is currently in use by another operation" + " and cannot be enabled", name); return; } @@ -2940,10 +2969,10 @@ void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name, return; } - if (bdrv_dirty_bitmap_frozen(bitmap)) { + if (bdrv_dirty_bitmap_user_locked(bitmap)) { error_setg(errp, - "Bitmap '%s' is currently frozen and cannot be disabled", - name); + "Bitmap '%s' is currently in use by another operation" + " and cannot be disabled", name); return; } @@ -2961,23 +2990,13 @@ void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name, return; } - if (bdrv_dirty_bitmap_frozen(dst)) { - error_setg(errp, "Bitmap '%s' is frozen and cannot be modified", - dst_name); - return; - } else if (bdrv_dirty_bitmap_readonly(dst)) { - error_setg(errp, "Bitmap '%s' is readonly and cannot be modified", - dst_name); - return; - } - src = bdrv_find_dirty_bitmap(bs, src_name); if (!src) { error_setg(errp, "Dirty bitmap '%s' not found", src_name); return; } - bdrv_merge_dirty_bitmap(dst, src, errp); + bdrv_merge_dirty_bitmap(dst, src, NULL, errp); } BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, @@ -3494,10 +3513,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, bdrv_unref(target_bs); goto out; } - if (bdrv_dirty_bitmap_qmp_locked(bmap)) { + if (bdrv_dirty_bitmap_user_locked(bmap)) { error_setg(errp, - "Bitmap '%s' is currently locked and cannot be used for " - "backup", backup->bitmap); + "Bitmap '%s' is currently in use by another operation" + " and cannot be used for backup", backup->bitmap); goto out; } } @@ -3544,6 +3563,7 @@ 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; @@ -3594,6 +3614,21 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, 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_user_locked(bmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be used for backup", backup->bitmap); + goto out; + } + } + if (!backup->auto_finalize) { job_flags |= JOB_MANUAL_FINALIZE; } @@ -3601,7 +3636,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, job_flags |= JOB_MANUAL_DISMISS; } job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, - backup->sync, NULL, backup->compress, + backup->sync, bmap, backup->compress, backup->on_source_error, backup->on_target_error, job_flags, NULL, NULL, txn, &local_err); if (local_err != NULL) {