diff --git a/blockdev.c b/blockdev.c index 16242972961a..53d4edfe2009 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1940,44 +1940,6 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp) } } - -static void eject_device(BlockBackend *blk, int force, Error **errp) -{ - BlockDriverState *bs = blk_bs(blk); - AioContext *aio_context; - - if (!bs) { - /* No medium inserted, so there is nothing to do */ - return; - } - - aio_context = bdrv_get_aio_context(bs); - aio_context_acquire(aio_context); - - if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) { - goto out; - } - if (!blk_dev_has_removable_media(blk)) { - error_setg(errp, "Device '%s' is not removable", - bdrv_get_device_name(bs)); - goto out; - } - - if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) { - blk_dev_eject_request(blk, force); - if (!force) { - error_setg(errp, "Device '%s' is locked", - bdrv_get_device_name(bs)); - goto out; - } - } - - bdrv_close(bs); - -out: - aio_context_release(aio_context); -} - void qmp_eject(const char *device, bool has_force, bool force, Error **errp) { Error *local_err = NULL; @@ -2015,78 +1977,6 @@ void qmp_block_passwd(bool has_device, const char *device, aio_context_release(aio_context); } -/* Assumes AioContext is held */ -static void qmp_bdrv_open_encrypted(BlockDriverState **pbs, - const char *filename, - int bdrv_flags, const char *format, - const char *password, Error **errp) -{ - Error *local_err = NULL; - QDict *options = NULL; - int ret; - - if (format) { - options = qdict_new(); - qdict_put(options, "driver", qstring_from_str(format)); - } - - ret = bdrv_open(pbs, filename, NULL, options, bdrv_flags, &local_err); - if (ret < 0) { - error_propagate(errp, local_err); - return; - } - - bdrv_add_key(*pbs, password, errp); -} - -void qmp_change_blockdev(const char *device, const char *filename, - const char *format, Error **errp) -{ - BlockBackend *blk; - BlockDriverState *bs; - AioContext *aio_context; - int bdrv_flags; - bool new_bs; - Error *err = NULL; - - blk = blk_by_name(device); - if (!blk) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", device); - return; - } - bs = blk_bs(blk); - new_bs = !bs; - - aio_context = blk_get_aio_context(blk); - aio_context_acquire(aio_context); - - eject_device(blk, 0, &err); - if (err) { - error_propagate(errp, err); - goto out; - } - - bdrv_flags = blk_is_read_only(blk) ? 0 : BDRV_O_RDWR; - bdrv_flags |= blk_get_root_state(blk)->open_flags & ~BDRV_O_RDWR; - - qmp_bdrv_open_encrypted(&bs, filename, bdrv_flags, format, NULL, &err); - if (err) { - error_propagate(errp, err); - goto out; - } - - if (new_bs) { - blk_insert_bs(blk, bs); - /* Has been sent automatically by bdrv_open() if blk_bs(blk) was not - * NULL */ - blk_dev_change_media_cb(blk, true); - } - -out: - aio_context_release(aio_context); -} - void qmp_blockdev_open_tray(const char *device, bool has_force, bool force, Error **errp) { @@ -2253,6 +2143,74 @@ void qmp_blockdev_insert_medium(const char *device, const char *node_name, qmp_blockdev_insert_anon_medium(device, bs, errp); } +void qmp_change_blockdev(const char *device, const char *filename, + const char *format, Error **errp) +{ + BlockBackend *blk; + BlockDriverState *medium_bs = NULL; + int bdrv_flags, ret; + QDict *options = NULL; + Error *err = NULL; + + blk = blk_by_name(device); + if (!blk) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", device); + goto fail; + } + + if (blk_bs(blk)) { + blk_update_root_state(blk); + } + + bdrv_flags = blk_get_open_flags_from_root_state(blk); + + if (format) { + options = qdict_new(); + qdict_put(options, "driver", qstring_from_str(format)); + } + + assert(!medium_bs); + ret = bdrv_open(&medium_bs, filename, NULL, options, bdrv_flags, errp); + if (ret < 0) { + goto fail; + } + + blk_apply_root_state(blk, medium_bs); + + bdrv_add_key(medium_bs, NULL, &err); + if (err) { + error_propagate(errp, err); + goto fail; + } + + qmp_blockdev_open_tray(device, false, false, &err); + if (err) { + error_propagate(errp, err); + goto fail; + } + + qmp_blockdev_remove_medium(device, &err); + if (err) { + error_propagate(errp, err); + goto fail; + } + + qmp_blockdev_insert_anon_medium(device, medium_bs, &err); + if (err) { + error_propagate(errp, err); + goto fail; + } + + qmp_blockdev_close_tray(device, errp); + +fail: + /* If the medium has been inserted, the device has its own reference, so + * ours must be relinquished; and if it has not been inserted successfully, + * the reference must be relinquished anyway */ + bdrv_unref(medium_bs); +} + /* throttling disk I/O limits */ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, int64_t bps_wr,