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:
parent
4e855baabf
commit
fa40e65622
79
blockdev.c
79
blockdev.c
@ -2367,6 +2367,85 @@ void qmp_block_job_complete(const char *device, Error **errp)
|
|||||||
block_job_complete(job, 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)
|
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||||
{
|
{
|
||||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||||
|
@ -679,6 +679,32 @@
|
|||||||
{ 'command': 'blockdev-snapshot-sync',
|
{ 'command': 'blockdev-snapshot-sync',
|
||||||
'data': 'BlockdevSnapshot' }
|
'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
|
# @block-commit
|
||||||
#
|
#
|
||||||
|
@ -1350,6 +1350,45 @@ Example:
|
|||||||
"format": "qcow2" } }
|
"format": "qcow2" } }
|
||||||
<- { "return": {} }
|
<- { "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
|
EQMP
|
||||||
|
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user