Skip to content

Commit

Permalink
blockdev: Implement change with basic operations
Browse files Browse the repository at this point in the history
Implement 'change' on block devices by calling blockdev-open-tray,
blockdev-remove-medium, blockdev-insert-medium (a variation of that
which does not need a node-name) and blockdev-close-tray.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
  • Loading branch information
XanClic authored and kevmw committed Nov 11, 2015
1 parent 38f54bd commit de2c6c0
Showing 1 changed file with 68 additions and 110 deletions.
178 changes: 68 additions & 110 deletions blockdev.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit de2c6c0

Please sign in to comment.