diff options
Diffstat (limited to 'blockdev.c')
| -rw-r--r-- | blockdev.c | 154 |
1 files changed, 128 insertions, 26 deletions
diff --git a/blockdev.c b/blockdev.c index 1fbfd3a2c4..c31bf3d98d 100644 --- a/blockdev.c +++ b/blockdev.c @@ -150,7 +150,7 @@ void blockdev_mark_auto_del(BlockBackend *blk) aio_context_acquire(aio_context); if (bs->job) { - block_job_cancel(bs->job); + block_job_cancel(bs->job, false); } aio_context_release(aio_context); @@ -334,7 +334,8 @@ static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals, case QTYPE_QSTRING: { unsigned long long length; - const char *str = qstring_get_str(qobject_to_qstring(entry->value)); + const char *str = qstring_get_str(qobject_to(QString, + entry->value)); if (parse_uint_full(str, &length, 10) == 0 && length > 0 && length <= UINT_MAX) { block_acct_add_interval(stats, (unsigned) length); @@ -346,7 +347,7 @@ static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals, } case QTYPE_QNUM: { - int64_t length = qnum_get_int(qobject_to_qnum(entry->value)); + int64_t length = qnum_get_int(qobject_to(QNum, entry->value)); if (length > 0 && length <= UINT_MAX) { block_acct_add_interval(stats, (unsigned) length); @@ -2118,6 +2119,9 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, 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"); return; @@ -2862,6 +2866,11 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, "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); + return; } if (bdrv_dirty_bitmap_get_persistance(bitmap)) { @@ -2896,6 +2905,11 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, "Bitmap '%s' is currently frozen and cannot be modified", name); return; + } else if (bdrv_dirty_bitmap_qmp_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", @@ -3261,7 +3275,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, AioContext *aio_context; QDict *options = NULL; Error *local_err = NULL; - int flags; + int flags, job_flags = BLOCK_JOB_DEFAULT; int64_t size; bool set_backing_hd = false; @@ -3280,6 +3294,12 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, 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; } @@ -3370,12 +3390,24 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, bdrv_unref(target_bs); goto out; } + if (bdrv_dirty_bitmap_qmp_locked(bmap)) { + error_setg(errp, + "Bitmap '%s' is currently locked and cannot be used for " + "backup", backup->bitmap); + goto out; + } + } + if (!backup->auto_finalize) { + job_flags |= BLOCK_JOB_MANUAL_FINALIZE; + } + if (!backup->auto_dismiss) { + job_flags |= BLOCK_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, - BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); + job_flags, NULL, NULL, txn, &local_err); bdrv_unref(target_bs); if (local_err != NULL) { error_propagate(errp, local_err); @@ -3410,6 +3442,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, Error *local_err = NULL; AioContext *aio_context; BlockJob *job = NULL; + int job_flags = BLOCK_JOB_DEFAULT; if (!backup->has_speed) { backup->speed = 0; @@ -3423,6 +3456,12 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, 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; } @@ -3451,10 +3490,16 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, goto out; } } + if (!backup->auto_finalize) { + job_flags |= BLOCK_JOB_MANUAL_FINALIZE; + } + if (!backup->auto_dismiss) { + job_flags |= BLOCK_JOB_MANUAL_DISMISS; + } job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, backup->sync, NULL, backup->compress, backup->on_source_error, backup->on_target_error, - BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); + job_flags, NULL, NULL, txn, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); } @@ -3806,7 +3851,7 @@ void qmp_block_job_cancel(const char *device, } trace_qmp_block_job_cancel(job); - block_job_cancel(job); + block_job_user_cancel(job, force, errp); out: aio_context_release(aio_context); } @@ -3816,12 +3861,12 @@ void qmp_block_job_pause(const char *device, Error **errp) AioContext *aio_context; BlockJob *job = find_block_job(device, &aio_context, errp); - if (!job || block_job_user_paused(job)) { + if (!job) { return; } trace_qmp_block_job_pause(job); - block_job_user_pause(job); + block_job_user_pause(job, errp); aio_context_release(aio_context); } @@ -3830,12 +3875,12 @@ void qmp_block_job_resume(const char *device, Error **errp) AioContext *aio_context; BlockJob *job = find_block_job(device, &aio_context, errp); - if (!job || !block_job_user_paused(job)) { + if (!job) { return; } trace_qmp_block_job_resume(job); - block_job_user_resume(job); + block_job_user_resume(job, errp); aio_context_release(aio_context); } @@ -3853,6 +3898,34 @@ void qmp_block_job_complete(const char *device, Error **errp) aio_context_release(aio_context); } +void qmp_block_job_finalize(const char *id, Error **errp) +{ + AioContext *aio_context; + BlockJob *job = find_block_job(id, &aio_context, errp); + + if (!job) { + return; + } + + trace_qmp_block_job_finalize(job); + block_job_finalize(job, errp); + aio_context_release(aio_context); +} + +void qmp_block_job_dismiss(const char *id, Error **errp) +{ + AioContext *aio_context; + BlockJob *job = find_block_job(id, &aio_context, errp); + + if (!job) { + return; + } + + trace_qmp_block_job_dismiss(job); + block_job_dismiss(&job, errp); + aio_context_release(aio_context); +} + void qmp_change_backing_file(const char *device, const char *image_node_name, const char *backing_file, @@ -3972,7 +4045,6 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); QDict *qdict; - const QDictEntry *ent; Error *local_err = NULL; visit_type_BlockdevOptions(v, NULL, &options, &local_err); @@ -3982,23 +4054,10 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) } visit_complete(v, &obj); - qdict = qobject_to_qdict(obj); + qdict = qobject_to(QDict, obj); qdict_flatten(qdict); - /* - * Rewrite "backing": null to "backing": "" - * TODO Rewrite "" to null instead, and perhaps not even here - */ - for (ent = qdict_first(qdict); ent; ent = qdict_next(qdict, ent)) { - char *dot = strrchr(ent->key, '.'); - - if (!strcmp(dot ? dot + 1 : ent->key, "backing") - && qobject_type(ent->value) == QTYPE_QNULL) { - qdict_put(qdict, ent->key, qstring_new()); - } - } - if (!qdict_get_try_str(qdict, "node-name")) { error_setg(errp, "'node-name' must be specified for the root node"); goto fail; @@ -4180,6 +4239,49 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, aio_context_release(old_context); } +void qmp_x_block_latency_histogram_set( + const char *device, + bool has_boundaries, uint64List *boundaries, + bool has_boundaries_read, uint64List *boundaries_read, + bool has_boundaries_write, uint64List *boundaries_write, + bool has_boundaries_flush, uint64List *boundaries_flush, + Error **errp) +{ + BlockBackend *blk = blk_by_name(device); + BlockAcctStats *stats; + + if (!blk) { + error_setg(errp, "Device '%s' not found", device); + return; + } + stats = blk_get_stats(blk); + + if (!has_boundaries && !has_boundaries_read && !has_boundaries_write && + !has_boundaries_flush) + { + block_latency_histograms_clear(stats); + return; + } + + if (has_boundaries || has_boundaries_read) { + block_latency_histogram_set( + stats, BLOCK_ACCT_READ, + has_boundaries_read ? boundaries_read : boundaries); + } + + if (has_boundaries || has_boundaries_write) { + block_latency_histogram_set( + stats, BLOCK_ACCT_WRITE, + has_boundaries_write ? boundaries_write : boundaries); + } + + if (has_boundaries || has_boundaries_flush) { + block_latency_histogram_set( + stats, BLOCK_ACCT_FLUSH, + has_boundaries_flush ? boundaries_flush : boundaries); + } +} + QemuOptsList qemu_common_drive_opts = { .name = "drive", .head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head), |