X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=blockdev.c;h=32b04b478c73873cd54ad2d93a189ecdeeda268c;hb=4ecd4d16a0af714ff7d9a1ad2559c621bf27649f;hp=d4274efe559b18d4c5a437433431f05e8ef7790a;hpb=8aeaa055f5d3d4e87bf870892ba301eae57bdc1d;p=mirror_qemu.git diff --git a/blockdev.c b/blockdev.c index d4274efe55..32b04b478c 100644 --- a/blockdev.c +++ b/blockdev.c @@ -36,10 +36,12 @@ #include "block/blockjob.h" #include "block/throttle-groups.h" #include "monitor/monitor.h" +#include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/config-file.h" #include "qapi/qmp/types.h" #include "qapi-visit.h" +#include "qapi/qmp/qerror.h" #include "qapi/qmp-output-visitor.h" #include "qapi/util.h" #include "sysemu/sysemu.h" @@ -174,7 +176,7 @@ static int drive_index_to_unit_id(BlockInterfaceType type, int index) QemuOpts *drive_def(const char *optstr) { - return qemu_opts_parse(qemu_find_opts("drive"), optstr, 0); + return qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false); } QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, @@ -335,6 +337,12 @@ static bool check_throttle_config(ThrottleConfig *cfg, Error **errp) return false; } + if (throttle_max_is_missing_limit(cfg)) { + error_setg(errp, "bps_max/iops_max require corresponding" + " bps/iops values"); + return false; + } + return true; } @@ -393,13 +401,13 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, } } - if (qemu_opt_get_bool(opts, "cache.writeback", true)) { + if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) { bdrv_flags |= BDRV_O_CACHE_WB; } - if (qemu_opt_get_bool(opts, "cache.direct", false)) { + if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) { bdrv_flags |= BDRV_O_NOCACHE; } - if (qemu_opt_get_bool(opts, "cache.no-flush", false)) { + if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) { bdrv_flags |= BDRV_O_NO_FLUSH; } @@ -742,16 +750,16 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) } /* Specific options take precedence */ - if (!qemu_opt_get(all_opts, "cache.writeback")) { - qemu_opt_set_bool(all_opts, "cache.writeback", + if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_WB)) { + qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_WB, !!(flags & BDRV_O_CACHE_WB), &error_abort); } - if (!qemu_opt_get(all_opts, "cache.direct")) { - qemu_opt_set_bool(all_opts, "cache.direct", + if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_DIRECT)) { + qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_DIRECT, !!(flags & BDRV_O_NOCACHE), &error_abort); } - if (!qemu_opt_get(all_opts, "cache.no-flush")) { - qemu_opt_set_bool(all_opts, "cache.no-flush", + if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_NO_FLUSH)) { + qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_NO_FLUSH, !!(flags & BDRV_O_NO_FLUSH), &error_abort); } qemu_opt_unset(all_opts, "cache"); @@ -942,7 +950,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, &error_abort); if (arch_type == QEMU_ARCH_S390X) { - qemu_opt_set(devopts, "driver", "virtio-blk-s390", &error_abort); + qemu_opt_set(devopts, "driver", "virtio-blk-ccw", &error_abort); } else { qemu_opt_set(devopts, "driver", "virtio-blk-pci", &error_abort); } @@ -1111,7 +1119,8 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return NULL; } bs = blk_bs(blk); @@ -1300,7 +1309,8 @@ static void internal_snapshot_prepare(BlkTransactionState *common, /* 2. check for validation */ blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } bs = blk_bs(blk); @@ -1310,7 +1320,7 @@ static void internal_snapshot_prepare(BlkTransactionState *common, aio_context_acquire(state->aio_context); if (!bdrv_is_inserted(bs)) { - error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); + error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); return; } @@ -1412,9 +1422,8 @@ typedef struct ExternalSnapshotState { static void external_snapshot_prepare(BlkTransactionState *common, Error **errp) { - BlockDriver *drv; int flags, ret; - QDict *options = NULL; + QDict *options; Error *local_err = NULL; bool has_device = false; const char *device; @@ -1449,12 +1458,6 @@ static void external_snapshot_prepare(BlkTransactionState *common, } /* start processing */ - drv = bdrv_find_format(format); - if (!drv) { - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); - return; - } - state->old_bs = bdrv_lookup_bs(has_device ? device : NULL, has_node_name ? node_name : NULL, &local_err); @@ -1478,7 +1481,7 @@ static void external_snapshot_prepare(BlkTransactionState *common, aio_context_acquire(state->aio_context); if (!bdrv_is_inserted(state->old_bs)) { - error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); + error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); return; } @@ -1489,13 +1492,13 @@ static void external_snapshot_prepare(BlkTransactionState *common, if (!bdrv_is_read_only(state->old_bs)) { if (bdrv_flush(state->old_bs)) { - error_set(errp, QERR_IO_ERROR); + error_setg(errp, QERR_IO_ERROR); return; } } if (!bdrv_is_first_non_filter(state->old_bs)) { - error_set(errp, QERR_FEATURE_DISABLED, "snapshot"); + error_setg(errp, QERR_FEATURE_DISABLED, "snapshot"); return; } @@ -1513,17 +1516,18 @@ static void external_snapshot_prepare(BlkTransactionState *common, } } + options = qdict_new(); if (has_snapshot_node_name) { - options = qdict_new(); qdict_put(options, "node-name", qstring_from_str(snapshot_node_name)); } + qdict_put(options, "driver", qstring_from_str(format)); /* TODO Inherit bs->options or only take explicit options with an * extended QMP command? */ assert(state->new_bs == NULL); ret = bdrv_open(&state->new_bs, new_image_file, NULL, options, - flags | BDRV_O_NO_BACKING, drv, &local_err); + flags | BDRV_O_NO_BACKING, &local_err); /* We will manually add the backing_hd field to the bs later */ if (ret != 0) { error_propagate(errp, local_err); @@ -1580,7 +1584,8 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp) blk = blk_by_name(backup->device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", backup->device); return; } bs = blk_bs(blk); @@ -1850,7 +1855,8 @@ void qmp_eject(const char *device, bool has_force, bool force, Error **errp) blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } @@ -1883,13 +1889,19 @@ void qmp_block_passwd(bool has_device, const char *device, /* Assumes AioContext is held */ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename, - int bdrv_flags, BlockDriver *drv, + int bdrv_flags, const char *format, const char *password, Error **errp) { Error *local_err = NULL; + QDict *options = NULL; int ret; - ret = bdrv_open(&bs, filename, NULL, NULL, bdrv_flags, drv, &local_err); + if (format) { + options = qdict_new(); + qdict_put(options, "driver", qstring_from_str(format)); + } + + ret = bdrv_open(&bs, filename, NULL, options, bdrv_flags, &local_err); if (ret < 0) { error_propagate(errp, local_err); return; @@ -1904,13 +1916,13 @@ void qmp_change_blockdev(const char *device, const char *filename, BlockBackend *blk; BlockDriverState *bs; AioContext *aio_context; - BlockDriver *drv = NULL; int bdrv_flags; Error *err = NULL; blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } bs = blk_bs(blk); @@ -1918,14 +1930,6 @@ void qmp_change_blockdev(const char *device, const char *filename, aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - if (format) { - drv = bdrv_find_whitelisted_format(format, bs->read_only); - if (!drv) { - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); - goto out; - } - } - eject_device(blk, 0, &err); if (err) { error_propagate(errp, err); @@ -1935,7 +1939,7 @@ void qmp_change_blockdev(const char *device, const char *filename, bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR; bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0; - qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp); + qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, format, NULL, errp); out: aio_context_release(aio_context); @@ -1971,7 +1975,8 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } bs = blk_bs(blk); @@ -2159,9 +2164,6 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) return; } - /* quiesce block driver; prevent further io */ - bdrv_drain_all(); - bdrv_flush(bs); bdrv_close(bs); /* if we have a device attached to this BlockDriverState @@ -2202,17 +2204,17 @@ void qmp_block_resize(bool has_device, const char *device, aio_context_acquire(aio_context); if (!bdrv_is_first_non_filter(bs)) { - error_set(errp, QERR_FEATURE_DISABLED, "resize"); + error_setg(errp, QERR_FEATURE_DISABLED, "resize"); goto out; } if (size < 0) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size"); + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size"); goto out; } if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) { - error_set(errp, QERR_DEVICE_IN_USE, device); + error_setg(errp, QERR_DEVICE_IN_USE, device); goto out; } @@ -2224,16 +2226,16 @@ void qmp_block_resize(bool has_device, const char *device, case 0: break; case -ENOMEDIUM: - error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); + error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); break; case -ENOTSUP: - error_set(errp, QERR_UNSUPPORTED); + error_setg(errp, QERR_UNSUPPORTED); break; case -EACCES: error_setg(errp, "Device '%s' is read only", device); break; case -EBUSY: - error_set(errp, QERR_DEVICE_IN_USE, device); + error_setg(errp, QERR_DEVICE_IN_USE, device); break; default: error_setg_errno(errp, -ret, "Could not resize"); @@ -2291,7 +2293,8 @@ void qmp_block_stream(const char *device, blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } bs = blk_bs(blk); @@ -2306,7 +2309,7 @@ void qmp_block_stream(const char *device, if (has_base) { base_bs = bdrv_find_backing_image(bs, base); if (base_bs == NULL) { - error_set(errp, QERR_BASE_NOT_FOUND, base); + error_setg(errp, QERR_BASE_NOT_FOUND, base); goto out; } assert(bdrv_get_aio_context(base_bs) == aio_context); @@ -2365,7 +2368,8 @@ void qmp_block_commit(const char *device, * scenario in which all optional arguments are omitted. */ blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } bs = blk_bs(blk); @@ -2373,9 +2377,6 @@ void qmp_block_commit(const char *device, aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - /* drain all i/o before commits */ - bdrv_drain_all(); - if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, errp)) { goto out; } @@ -2403,7 +2404,7 @@ void qmp_block_commit(const char *device, } if (base_bs == NULL) { - error_set(errp, QERR_BASE_NOT_FOUND, base ? base : "NULL"); + error_setg(errp, QERR_BASE_NOT_FOUND, base ? base : "NULL"); goto out; } @@ -2456,7 +2457,7 @@ void qmp_drive_backup(const char *device, const char *target, BlockDriverState *source = NULL; BdrvDirtyBitmap *bmap = NULL; AioContext *aio_context; - BlockDriver *drv = NULL; + QDict *options = NULL; Error *local_err = NULL; int flags; int64_t size; @@ -2477,7 +2478,8 @@ void qmp_drive_backup(const char *device, const char *target, blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } bs = blk_bs(blk); @@ -2488,20 +2490,13 @@ void qmp_drive_backup(const char *device, const char *target, /* Although backup_run has this check too, we need to use bs->drv below, so * do an early check redundantly. */ if (!bdrv_is_inserted(bs)) { - error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); + error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); goto out; } if (!has_format) { format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name; } - if (format) { - drv = bdrv_find_format(format); - if (!drv) { - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); - goto out; - } - } /* Early check to avoid creating target */ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { @@ -2529,7 +2524,7 @@ void qmp_drive_backup(const char *device, const char *target, } if (mode != NEW_IMAGE_MODE_EXISTING) { - assert(format && drv); + assert(format); if (source) { bdrv_img_create(target, format, source->filename, source->drv->format_name, NULL, @@ -2545,8 +2540,13 @@ void qmp_drive_backup(const char *device, const char *target, goto out; } + if (format) { + options = qdict_new(); + qdict_put(options, "driver", qstring_from_str(format)); + } + target_bs = NULL; - ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err); + ret = bdrv_open(&target_bs, target, NULL, options, flags, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; @@ -2634,8 +2634,6 @@ out: aio_context_release(aio_context); } -#define DEFAULT_MIRROR_BUF_SIZE (10 << 20) - void qmp_drive_mirror(const char *device, const char *target, bool has_format, const char *format, bool has_node_name, const char *node_name, @@ -2647,15 +2645,15 @@ void qmp_drive_mirror(const char *device, const char *target, bool has_buf_size, int64_t buf_size, bool has_on_source_error, BlockdevOnError on_source_error, bool has_on_target_error, BlockdevOnError on_target_error, + bool has_unmap, bool unmap, Error **errp) { BlockBackend *blk; BlockDriverState *bs; BlockDriverState *source, *target_bs; AioContext *aio_context; - BlockDriver *drv = NULL; Error *local_err = NULL; - QDict *options = NULL; + QDict *options; int flags; int64_t size; int ret; @@ -2676,22 +2674,27 @@ void qmp_drive_mirror(const char *device, const char *target, granularity = 0; } if (!has_buf_size) { - buf_size = DEFAULT_MIRROR_BUF_SIZE; + buf_size = 0; + } + if (!has_unmap) { + unmap = true; } if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", - "a value in range [512B, 64MB]"); + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", + "a value in range [512B, 64MB]"); return; } if (granularity & (granularity - 1)) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", "power of 2"); + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", + "power of 2"); return; } blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } bs = blk_bs(blk); @@ -2700,20 +2703,13 @@ void qmp_drive_mirror(const char *device, const char *target, aio_context_acquire(aio_context); if (!bdrv_is_inserted(bs)) { - error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); + error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); goto out; } if (!has_format) { format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name; } - if (format) { - drv = bdrv_find_format(format); - if (!drv) { - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); - goto out; - } - } if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) { goto out; @@ -2745,7 +2741,7 @@ void qmp_drive_mirror(const char *device, const char *target, goto out; } - to_replace_bs = check_to_replace_node(replaces, &local_err); + to_replace_bs = check_to_replace_node(bs, replaces, &local_err); if (!to_replace_bs) { error_propagate(errp, local_err); @@ -2768,7 +2764,7 @@ void qmp_drive_mirror(const char *device, const char *target, && mode != NEW_IMAGE_MODE_EXISTING) { /* create new image w/o backing file */ - assert(format && drv); + assert(format); bdrv_img_create(target, format, NULL, NULL, NULL, size, flags, &local_err, false); } else { @@ -2792,17 +2788,20 @@ void qmp_drive_mirror(const char *device, const char *target, goto out; } + options = qdict_new(); if (has_node_name) { - options = qdict_new(); qdict_put(options, "node-name", qstring_from_str(node_name)); } + if (format) { + qdict_put(options, "driver", qstring_from_str(format)); + } /* Mirroring takes care of copy-on-write using the source's backing * file. */ target_bs = NULL; ret = bdrv_open(&target_bs, target, NULL, options, - flags | BDRV_O_NO_BACKING, drv, &local_err); + flags | BDRV_O_NO_BACKING, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; @@ -2817,6 +2816,7 @@ void qmp_drive_mirror(const char *device, const char *target, has_replaces ? replaces : NULL, speed, granularity, buf_size, sync, on_source_error, on_target_error, + unmap, block_job_cb, bs, &local_err); if (local_err != NULL) { bdrv_unref(target_bs); @@ -2957,7 +2957,8 @@ void qmp_change_backing_file(const char *device, blk = blk_by_name(device); if (!blk) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); return; } bs = blk_bs(blk); @@ -3121,15 +3122,15 @@ QemuOptsList qemu_common_drive_opts = { .type = QEMU_OPT_STRING, .help = "discard operation (ignore/off, unmap/on)", },{ - .name = "cache.writeback", + .name = BDRV_OPT_CACHE_WB, .type = QEMU_OPT_BOOL, .help = "enables writeback mode for any caches", },{ - .name = "cache.direct", + .name = BDRV_OPT_CACHE_DIRECT, .type = QEMU_OPT_BOOL, .help = "enables use of O_DIRECT (bypass the host page cache)", },{ - .name = "cache.no-flush", + .name = BDRV_OPT_CACHE_NO_FLUSH, .type = QEMU_OPT_BOOL, .help = "ignore any flush requests for the device", },{