summaryrefslogtreecommitdiffstats
path: root/blockdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'blockdev.c')
-rw-r--r--blockdev.c171
1 files changed, 103 insertions, 68 deletions
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) {