From: Kevin Wolf <kwolf@redhat.com>
To: Alberto Garcia <berto@igalia.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>,
qemu-devel@nongnu.org, qemu-block@nongnu.org,
Max Reitz <mreitz@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v6 3/4] block: add a 'blockdev-snapshot' QMP command
Date: Tue, 6 Oct 2015 17:30:07 +0200 [thread overview]
Message-ID: <20151006153007.GC24770@noname.str.redhat.com> (raw)
In-Reply-To: <8cc989a360a5fe38839144946c878fb9f8c6a6d5.1442928283.git.berto@igalia.com>
Am 22.09.2015 um 15:28 hat Alberto Garcia geschrieben:
> One of the limitations of the 'blockdev-snapshot-sync' command is that
> it does not allow passing BlockdevOptions to the newly created
> snapshots, so they are always opened using the default values.
>
> Extending the command to allow passing options is not a practical
> solution because there is overlap between those options and some of
> the existing parameters of the command.
>
> This patch introduces a new 'blockdev-snapshot' command with a simpler
> interface: it just takes two references to existing block devices that
> will be used as the source and target for the snapshot.
>
> Since the main difference between the two commands is that one of them
> creates and opens the target image, while the other uses an already
> opened one, the bulk of the implementation is shared.
>
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Cc: Eric Blake <eblake@redhat.com>
> Cc: Max Reitz <mreitz@redhat.com>
> ---
> blockdev.c | 163 ++++++++++++++++++++++++++++++++-------------------
> qapi-schema.json | 2 +
> qapi/block-core.json | 28 +++++++++
> qmp-commands.hx | 38 ++++++++++++
> 4 files changed, 171 insertions(+), 60 deletions(-)
>
> diff --git a/blockdev.c b/blockdev.c
> index 1a5b889..daf72f3 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1183,6 +1183,18 @@ void qmp_blockdev_snapshot_sync(bool has_device, const char *device,
> &snapshot, errp);
> }
>
> +void qmp_blockdev_snapshot(const char *node, const char *overlay,
> + Error **errp)
> +{
> + BlockdevSnapshot snapshot_data = {
> + .node = (char *) node,
> + .overlay = (char *) overlay
> + };
> +
> + blockdev_do_action(TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT,
> + &snapshot_data, errp);
> +}
> +
> void qmp_blockdev_snapshot_internal_sync(const char *device,
> const char *name,
> Error **errp)
> @@ -1521,57 +1533,48 @@ typedef struct ExternalSnapshotState {
> static void external_snapshot_prepare(BlkTransactionState *common,
> Error **errp)
> {
> - int flags, ret;
> - QDict *options;
> + int flags = 0, ret;
> + QDict *options = NULL;
> Error *local_err = NULL;
> - bool has_device = false;
> + /* Device and node name of the image to generate the snapshot from */
> const char *device;
> - bool has_node_name = false;
> const char *node_name;
> - bool has_snapshot_node_name = false;
> - const char *snapshot_node_name;
> + /* Reference to the new image (for 'blockdev-snapshot') */
> + const char *snapshot_ref;
> + /* File name of the new image (for 'blockdev-snapshot-sync') */
> const char *new_image_file;
> - const char *format = "qcow2";
> - enum NewImageMode mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
> ExternalSnapshotState *state =
> DO_UPCAST(ExternalSnapshotState, common, common);
> TransactionAction *action = common->action;
>
> - /* get parameters */
> - g_assert(action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC);
> -
> - has_device = action->blockdev_snapshot_sync->has_device;
> - device = action->blockdev_snapshot_sync->device;
> - has_node_name = action->blockdev_snapshot_sync->has_node_name;
> - node_name = action->blockdev_snapshot_sync->node_name;
> - has_snapshot_node_name =
> - action->blockdev_snapshot_sync->has_snapshot_node_name;
> - snapshot_node_name = action->blockdev_snapshot_sync->snapshot_node_name;
> -
> - new_image_file = action->blockdev_snapshot_sync->snapshot_file;
> - if (action->blockdev_snapshot_sync->has_format) {
> - format = action->blockdev_snapshot_sync->format;
> - }
> - if (action->blockdev_snapshot_sync->has_mode) {
> - mode = action->blockdev_snapshot_sync->mode;
> + /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
> + * purpose but a different set of parameters */
> + switch (action->kind) {
> + case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT:
> + {
> + BlockdevSnapshot *s = action->blockdev_snapshot;
> + device = s->node;
> + node_name = s->node;
> + new_image_file = NULL;
> + snapshot_ref = s->overlay;
> + }
> + break;
> + case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC:
> + {
> + BlockdevSnapshotSync *s = action->blockdev_snapshot_sync;
> + device = s->has_device ? s->device : NULL;
> + node_name = s->has_node_name ? s->node_name : NULL;
> + new_image_file = s->snapshot_file;
> + snapshot_ref = NULL;
> + }
> + break;
> + default:
> + g_assert_not_reached();
> }
>
> /* start processing */
> - state->old_bs = bdrv_lookup_bs(has_device ? device : NULL,
> - has_node_name ? node_name : NULL,
> - &local_err);
> - if (local_err) {
> - error_propagate(errp, local_err);
> - return;
> - }
> -
> - if (has_node_name && !has_snapshot_node_name) {
> - error_setg(errp, "New snapshot node name missing");
> - return;
> - }
> -
> - if (has_snapshot_node_name && bdrv_find_node(snapshot_node_name)) {
> - error_setg(errp, "New snapshot node name already existing");
> + state->old_bs = bdrv_lookup_bs(device, node_name, errp);
> + if (!state->old_bs) {
> return;
> }
>
> @@ -1601,35 +1604,69 @@ static void external_snapshot_prepare(BlkTransactionState *common,
> return;
> }
>
> - flags = state->old_bs->open_flags;
> + if (action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
> + BlockdevSnapshotSync *s = action->blockdev_snapshot_sync;
> + const char *format = s->has_format ? s->format : "qcow2";
> + enum NewImageMode mode;
> + const char *snapshot_node_name =
> + s->has_snapshot_node_name ? s->snapshot_node_name : NULL;
>
> - /* create new image w/backing file */
> - if (mode != NEW_IMAGE_MODE_EXISTING) {
> - bdrv_img_create(new_image_file, format,
> - state->old_bs->filename,
> - state->old_bs->drv->format_name,
> - NULL, -1, flags, &local_err, false);
> - if (local_err) {
> - error_propagate(errp, local_err);
> + if (node_name && !snapshot_node_name) {
> + error_setg(errp, "New snapshot node name missing");
> return;
> }
> - }
>
> - options = qdict_new();
> - if (has_snapshot_node_name) {
> - qdict_put(options, "node-name",
> - qstring_from_str(snapshot_node_name));
> + if (snapshot_node_name && bdrv_find_node(snapshot_node_name)) {
> + error_setg(errp, "New snapshot node name already exists");
> + return;
> + }
Preexisting, but shouldn't we use bdrv_lookup_bs() here (because devices
and node names share a namespace)?
Otherwise, we could decide to drop the check altogether (because
bdrv_open() already checks this), but then we would already have created
the new image.
> +
> + flags = state->old_bs->open_flags;
> +
> + /* create new image w/backing file */
> + mode = s->has_mode ? s->mode : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
> + if (mode != NEW_IMAGE_MODE_EXISTING) {
> + bdrv_img_create(new_image_file, format,
> + state->old_bs->filename,
> + state->old_bs->drv->format_name,
> + NULL, -1, flags, &local_err, false);
> + if (local_err) {
> + error_propagate(errp, local_err);
> + return;
> + }
> + }
> +
> + options = qdict_new();
> + if (s->has_snapshot_node_name) {
> + qdict_put(options, "node-name",
> + qstring_from_str(snapshot_node_name));
> + }
> + qdict_put(options, "driver", qstring_from_str(format));
> +
> + flags |= BDRV_O_NO_BACKING;
> }
> - qdict_put(options, "driver", qstring_from_str(format));
>
> - /* TODO Inherit bs->options or only take explicit options with an
> - * extended QMP command? */
> assert(state->new_bs == NULL);
> - ret = bdrv_open(&state->new_bs, new_image_file, NULL, options,
> - flags | BDRV_O_NO_BACKING, &local_err);
> + ret = bdrv_open(&state->new_bs, new_image_file, snapshot_ref, options,
> + flags, errp);
> /* We will manually add the backing_hd field to the bs later */
> if (ret != 0) {
> - error_propagate(errp, local_err);
> + return;
> + }
> +
> + if (state->new_bs->blk != NULL) {
> + error_setg(errp, "The snapshot is already in use by %s",
> + blk_name(state->new_bs->blk));
> + return;
> + }
Is it even possible yet to create a root BDS without a BB?
> + if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
> + errp)) {
> + return;
> + }
> +
> + if (state->new_bs->backing_hd != NULL) {
> + error_setg(errp, "The snapshot already has a backing image");
> }
The error cases after bdrv_open() should probably bdrv_unref() the node.
Kevin
next prev parent reply other threads:[~2015-10-06 15:30 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-22 13:28 [Qemu-devel] [PATCH v6 0/4] Add 'blockdev-snapshot' command Alberto Garcia
2015-09-22 13:28 ` [Qemu-devel] [PATCH v6 1/4] block: rename BlockdevSnapshot to BlockdevSnapshotSync Alberto Garcia
2015-10-06 15:31 ` Kevin Wolf
2015-09-22 13:28 ` [Qemu-devel] [PATCH v6 2/4] block: support passing 'backing': '' to 'blockdev-add' Alberto Garcia
2015-10-06 15:31 ` Kevin Wolf
2015-09-22 13:28 ` [Qemu-devel] [PATCH v6 3/4] block: add a 'blockdev-snapshot' QMP command Alberto Garcia
2015-09-22 16:38 ` Max Reitz
2015-09-23 8:59 ` Alberto Garcia
2015-10-06 15:30 ` Kevin Wolf [this message]
2015-10-06 15:49 ` Alberto Garcia
2015-10-07 7:34 ` Kevin Wolf
2015-09-22 13:28 ` [Qemu-devel] [PATCH v6 4/4] block: add tests for the 'blockdev-snapshot' command Alberto Garcia
2015-09-22 16:54 ` Max Reitz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20151006153007.GC24770@noname.str.redhat.com \
--to=kwolf@redhat.com \
--cc=berto@igalia.com \
--cc=mreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.