From: Federico Simoncelli <fsimo...@redhat.com> Signed-off-by: Federico Simoncelli <fsimo...@redhat.com> Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- blockdev.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hmp-commands.hx | 16 +++++++++++++ hmp.c | 11 +++++++++ hmp.h | 1 + qapi-schema.json | 22 ++++++++++++++++++ qmp-commands.hx | 30 +++++++++++++++++++++++++ 6 files changed, 143 insertions(+), 0 deletions(-)
diff --git a/blockdev.c b/blockdev.c index 2958419..df8ce14 100644 --- a/blockdev.c +++ b/blockdev.c @@ -646,6 +646,69 @@ void do_commit(Monitor *mon, const QDict *qdict) } } +static void change_blockdev_image(const char *device, const char *new_image_file, + const char *format, Error **errp) +{ + BlockDriverState *bs; + BlockDriver *drv, *old_drv, *proto_drv; + int ret = 0; + int flags; + char old_filename[1024]; + + bs = bdrv_find(device); + if (!bs) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return; + } + if (bdrv_in_use(bs)) { + error_set(errp, QERR_DEVICE_IN_USE, device); + return; + } + + pstrcpy(old_filename, sizeof(old_filename), bs->filename); + + old_drv = bs->drv; + flags = bs->open_flags; + + drv = bdrv_find_format(format); + if (!drv) { + error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); + return; + } + + proto_drv = bdrv_find_protocol(new_image_file); + if (!proto_drv) { + error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); + return; + } + + bdrv_drain_all(); + bdrv_flush(bs); + + bdrv_close(bs); + ret = bdrv_open(bs, new_image_file, flags, drv); + /* + * If reopening the image file we just created fails, fall back + * and try to re-open the original image. If that fails too, we + * are in serious trouble. + */ + if (ret != 0) { + ret = bdrv_open(bs, old_filename, flags, old_drv); + if (ret != 0) { + error_set(errp, QERR_OPEN_FILE_FAILED, old_filename); + } else { + error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file); + } + } +} + +void qmp_drive_reopen(const char *device, const char *new_image_file, + bool has_format, const char *format, Error **errp) +{ + change_blockdev_image(device, new_image_file, + has_format ? format : "qcow2", errp); +} + static void blockdev_do_action(int kind, void *data, Error **errp) { BlockdevAction action; diff --git a/hmp-commands.hx b/hmp-commands.hx index 9c49c33..4afde71 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -925,6 +925,22 @@ using the specified target. ETEXI { + .name = "drive_reopen", + .args_type = "device:B,new-image-file:s,format:s?", + .params = "device new-image-file [format]", + .help = "Assigns a new image file to a device.\n\t\t\t" + "The image will be opened using the format\n\t\t\t" + "specified or 'qcow2' by default.\n\t\t\t", + .mhandler.cmd = hmp_drive_reopen, + }, + +STEXI +@item drive_reopen +@findex drive_reopen +Assigns a new image file to a device. +ETEXI + + { .name = "drive_add", .args_type = "pci_addr:s,opts:s", .params = "[[<domain>:]<bus>:]<slot>\n" diff --git a/hmp.c b/hmp.c index e706db9..ec41d83 100644 --- a/hmp.c +++ b/hmp.c @@ -738,6 +738,17 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &errp); } +void hmp_drive_reopen(Monitor *mon, const QDict *qdict) +{ + const char *device = qdict_get_str(qdict, "device"); + const char *filename = qdict_get_str(qdict, "new-image-file"); + const char *format = qdict_get_try_str(qdict, "format"); + Error *errp = NULL; + + qmp_drive_reopen(device, filename, !!format, format, &errp); + hmp_handle_error(mon, &errp); +} + void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) { qmp_migrate_cancel(NULL); diff --git a/hmp.h b/hmp.h index 5352f00..648a84f 100644 --- a/hmp.h +++ b/hmp.h @@ -49,6 +49,7 @@ void hmp_balloon(Monitor *mon, const QDict *qdict); void hmp_block_resize(Monitor *mon, const QDict *qdict); void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict); void hmp_drive_mirror(Monitor *mon, const QDict *qdict); +void hmp_drive_reopen(Monitor *mon, const QDict *qdict); void hmp_migrate_cancel(Monitor *mon, const QDict *qdict); void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict); void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict); diff --git a/qapi-schema.json b/qapi-schema.json index 4cebf78..21eb256 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1235,6 +1235,28 @@ '*mode': 'NewImageMode'} } ## +# @drive-reopen +# +# Assigns a new image file to a device. +# +# @device: the name of the device for which we are changing the image file. +# +# @new-image-file: the target of the new image. If the file doesn't exists the +# command will fail. +# +# @format: #optional the format of the new image, default is 'qcow2'. +# +# Returns: nothing on success +# If @device is not a valid block device, DeviceNotFound +# If @new-image-file can't be opened, OpenFileFailed +# If @format is invalid, InvalidBlockFormat +# +# Since 1.1 +## +{ 'command': 'drive-reopen', + 'data': { 'device': 'str', 'new-image-file': 'str', '*format': 'str' } } + +## # @human-monitor-command: # # Execute a command on the human monitor and return the output. diff --git a/qmp-commands.hx b/qmp-commands.hx index 122ebe7..7fc30c2 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -818,6 +818,36 @@ Example: EQMP { + .name = "drive-reopen", + .args_type = "device:B,new-image-file:s,format:s?", + .mhandler.cmd_new = qmp_marshal_input_drive_reopen, + }, + +SQMP +drive-reopen +------------ + +Assigns a new image file to a device. Except extremely rare cases where the +guest is expecting the drive to change its content, the new image should +contain the same data of the current one. One use case is to terminate +a drive-mirror command. + +Arguments: + +- "device": device name to operate on (json-string) +- "new-image-file": name of new image file (json-string) +- "format": format of new image (json-string, optional) + +Example: + +-> { "execute": "drive-reopen", "arguments": {"device": "ide-hd0", + "new-image-file": "/some/place/my-image", + "format": "qcow2" } } +<- { "return": {} } + +EQMP + + { .name = "balloon", .args_type = "value:M", .mhandler.cmd_new = qmp_marshal_input_balloon, -- 1.7.7.6