blockdev: Implement change with basic operations
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>
This commit is contained in:
		
							parent
							
								
									38f54bd1ee
								
							
						
					
					
						commit
						de2c6c0536
					
				
							
								
								
									
										178
									
								
								blockdev.c
								
								
								
								
							
							
						
						
									
										178
									
								
								blockdev.c
								
								
								
								
							| 
						 | 
				
			
			@ -1940,44 +1940,6 @@ exit:
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue