summaryrefslogtreecommitdiffstats
path: root/blockdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'blockdev.c')
-rw-r--r--blockdev.c83
1 files changed, 66 insertions, 17 deletions
diff --git a/blockdev.c b/blockdev.c
index 2431448c5d..93417f6302 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2500,19 +2500,39 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
bool has_base, const char *base,
bool has_base_node, const char *base_node,
bool has_backing_file, const char *backing_file,
+ bool has_bottom, const char *bottom,
bool has_speed, int64_t speed,
bool has_on_error, BlockdevOnError on_error,
+ bool has_filter_node_name, const char *filter_node_name,
bool has_auto_finalize, bool auto_finalize,
bool has_auto_dismiss, bool auto_dismiss,
Error **errp)
{
- BlockDriverState *bs, *iter;
+ BlockDriverState *bs, *iter, *iter_end;
BlockDriverState *base_bs = NULL;
+ BlockDriverState *bottom_bs = NULL;
AioContext *aio_context;
Error *local_err = NULL;
- const char *base_name = NULL;
int job_flags = JOB_DEFAULT;
+ if (has_base && has_base_node) {
+ error_setg(errp, "'base' and 'base-node' cannot be specified "
+ "at the same time");
+ return;
+ }
+
+ if (has_base && has_bottom) {
+ error_setg(errp, "'base' and 'bottom' cannot be specified "
+ "at the same time");
+ return;
+ }
+
+ if (has_bottom && has_base_node) {
+ error_setg(errp, "'bottom' and 'base-node' cannot be specified "
+ "at the same time");
+ return;
+ }
+
if (!has_on_error) {
on_error = BLOCKDEV_ON_ERROR_REPORT;
}
@@ -2525,12 +2545,6 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
- if (has_base && has_base_node) {
- error_setg(errp, "'base' and 'base-node' cannot be specified "
- "at the same time");
- goto out;
- }
-
if (has_base) {
base_bs = bdrv_find_backing_image(bs, base);
if (base_bs == NULL) {
@@ -2538,7 +2552,6 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
goto out;
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
- base_name = base;
}
if (has_base_node) {
@@ -2553,11 +2566,35 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
bdrv_refresh_filename(base_bs);
- base_name = base_bs->filename;
}
- /* Check for op blockers in the whole chain between bs and base */
- for (iter = bs; iter && iter != base_bs;
+ if (has_bottom) {
+ bottom_bs = bdrv_lookup_bs(NULL, bottom, errp);
+ if (!bottom_bs) {
+ goto out;
+ }
+ if (!bottom_bs->drv) {
+ error_setg(errp, "Node '%s' is not open", bottom);
+ goto out;
+ }
+ if (bottom_bs->drv->is_filter) {
+ error_setg(errp, "Node '%s' is a filter, use a non-filter node "
+ "as 'bottom'", bottom);
+ goto out;
+ }
+ if (!bdrv_chain_contains(bs, bottom_bs)) {
+ error_setg(errp, "Node '%s' is not in a chain starting from '%s'",
+ bottom, device);
+ goto out;
+ }
+ assert(bdrv_get_aio_context(bottom_bs) == aio_context);
+ }
+
+ /*
+ * Check for op blockers in the whole chain between bs and base (or bottom)
+ */
+ iter_end = has_bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs;
+ for (iter = bs; iter && iter != iter_end;
iter = bdrv_filter_or_cow_bs(iter))
{
if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) {
@@ -2573,9 +2610,6 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
goto out;
}
- /* backing_file string overrides base bs filename */
- base_name = has_backing_file ? backing_file : base_name;
-
if (has_auto_finalize && !auto_finalize) {
job_flags |= JOB_MANUAL_FINALIZE;
}
@@ -2583,8 +2617,9 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
job_flags |= JOB_MANUAL_DISMISS;
}
- stream_start(has_job_id ? job_id : NULL, bs, base_bs, base_name,
- job_flags, has_speed ? speed : 0, on_error, &local_err);
+ stream_start(has_job_id ? job_id : NULL, bs, base_bs, backing_file,
+ bottom_bs, job_flags, has_speed ? speed : 0, on_error,
+ filter_node_name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
@@ -2794,6 +2829,7 @@ static BlockJob *do_backup_common(BackupCommon *backup,
{
BlockJob *job = NULL;
BdrvDirtyBitmap *bmap = NULL;
+ BackupPerf perf = { .max_workers = 64 };
int job_flags = JOB_DEFAULT;
if (!backup->has_speed) {
@@ -2818,6 +2854,18 @@ static BlockJob *do_backup_common(BackupCommon *backup,
backup->compress = false;
}
+ if (backup->x_perf) {
+ if (backup->x_perf->has_use_copy_range) {
+ perf.use_copy_range = backup->x_perf->use_copy_range;
+ }
+ if (backup->x_perf->has_max_workers) {
+ perf.max_workers = backup->x_perf->max_workers;
+ }
+ if (backup->x_perf->has_max_chunk) {
+ perf.max_chunk = backup->x_perf->max_chunk;
+ }
+ }
+
if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
(backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
/* done before desugaring 'incremental' to print the right message */
@@ -2891,6 +2939,7 @@ static BlockJob *do_backup_common(BackupCommon *backup,
backup->sync, bmap, backup->bitmap_mode,
backup->compress,
backup->filter_node_name,
+ &perf,
backup->on_source_error,
backup->on_target_error,
job_flags, NULL, NULL, txn, errp);