block: add QAPI command to allow live backing file change

This allows a user to make a live change to the backing file recorded in
an open image.

The image file to modify can be specified 2 ways:

1) image filename
2) image node-name

Note: this does not cause the backing file itself to be reopened; it
merely changes the backing filename in the image file structure, and
in internal BDS structures.

It is the responsibility of the user to pass a filename string that
can be resolved when the image chain is reopened, and the filename
string is not validated.

A good analogy for this command is that it is a live version of
'qemu-img rebase -u', with respect to changing the backing file string.

[Jeff is offline so I respun this patch in his absence.  Dropped image
filename since using node-name is preferred and this is a new command.
No need to introduce the limitations of finding images by filename.
--Stefan]

Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Jeff Cody 2014-07-01 09:52:16 +02:00 committed by Stefan Hajnoczi
parent 4e855baabf
commit fa40e65622
3 changed files with 144 additions and 0 deletions

View File

@ -2367,6 +2367,85 @@ void qmp_block_job_complete(const char *device, Error **errp)
block_job_complete(job, errp);
}
void qmp_change_backing_file(const char *device,
const char *image_node_name,
const char *backing_file,
Error **errp)
{
BlockDriverState *bs = NULL;
BlockDriverState *image_bs = NULL;
Error *local_err = NULL;
bool ro;
int open_flags;
int ret;
/* find the top layer BDS of the chain */
bs = bdrv_find(device);
if (!bs) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (!image_bs) {
error_setg(errp, "image file not found");
return;
}
if (bdrv_find_base(image_bs) == image_bs) {
error_setg(errp, "not allowing backing file change on an image "
"without a backing file");
return;
}
/* even though we are not necessarily operating on bs, we need it to
* determine if block ops are currently prohibited on the chain */
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
return;
}
/* final sanity check */
if (!bdrv_chain_contains(bs, image_bs)) {
error_setg(errp, "'%s' and image file are not in the same chain",
device);
return;
}
/* if not r/w, reopen to make r/w */
open_flags = image_bs->open_flags;
ro = bdrv_is_read_only(image_bs);
if (ro) {
bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
ret = bdrv_change_backing_file(image_bs, backing_file,
image_bs->drv ? image_bs->drv->format_name : "");
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not change backing file to '%s'",
backing_file);
/* don't exit here, so we can try to restore open flags if
* appropriate */
}
if (ro) {
bdrv_reopen(image_bs, open_flags, &local_err);
if (local_err) {
error_propagate(errp, local_err); /* will preserve prior errp */
}
}
}
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
{
QmpOutputVisitor *ov = qmp_output_visitor_new();

View File

@ -679,6 +679,32 @@
{ 'command': 'blockdev-snapshot-sync',
'data': 'BlockdevSnapshot' }
##
# @change-backing-file
#
# Change the backing file in the image file metadata. This does not
# cause QEMU to reopen the image file to reparse the backing filename
# (it may, however, perform a reopen to change permissions from
# r/o -> r/w -> r/o, if needed). The new backing file string is written
# into the image file metadata, and the QEMU internal strings are
# updated.
#
# @image-node-name: The name of the block driver state node of the
# image to modify.
#
# @device: The name of the device that owns image-node-name.
#
# @backing-file: The string to write as the backing file. This
# string is not validated, so care should be taken
# when specifying the string or the image chain may
# not be able to be reopened again.
#
# Since: 2.1
##
{ 'command': 'change-backing-file',
'data': { 'device': 'str', 'image-node-name': 'str',
'backing-file': 'str' } }
##
# @block-commit
#

View File

@ -1350,6 +1350,45 @@ Example:
"format": "qcow2" } }
<- { "return": {} }
EQMP
{
.name = "change-backing-file",
.args_type = "device:s,image-node-name:s,backing-file:s",
.mhandler.cmd_new = qmp_marshal_input_change_backing_file,
},
SQMP
change-backing-file
-------------------
Since: 2.1
Change the backing file in the image file metadata. This does not cause
QEMU to reopen the image file to reparse the backing filename (it may,
however, perform a reopen to change permissions from r/o -> r/w -> r/o,
if needed). The new backing file string is written into the image file
metadata, and the QEMU internal strings are updated.
Arguments:
- "image-node-name": The name of the block driver state node of the
image to modify. The "device" is argument is used to
verify "image-node-name" is in the chain described by
"device".
(json-string, optional)
- "device": The name of the device.
(json-string)
- "backing-file": The string to write as the backing file. This string is
not validated, so care should be taken when specifying
the string or the image chain may not be able to be
reopened again.
(json-string)
Returns: Nothing on success
If "device" does not exist or cannot be determined, DeviceNotFound
EQMP
{