From: Paolo Bonzini <pbonzini@redhat.com>
To: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Cc: Kevin Wolf <kwolf@redhat.com>,
stefanha@gmail.com, qemu-devel@nongnu.org, dietmar@proxmox.com
Subject: Re: [Qemu-devel] [PATCH 2/3] block: adjust qmp_transaction to be extendable
Date: Wed, 3 Apr 2013 03:21:12 -0400 (EDT) [thread overview]
Message-ID: <1466473402.1066275.1364973672613.JavaMail.root@redhat.com> (raw)
In-Reply-To: <515BC36F.7080307@linux.vnet.ibm.com>
----- Messaggio originale -----
> Da: "Wenchao Xia" <xiawenc@linux.vnet.ibm.com>
> A: "Kevin Wolf" <kwolf@redhat.com>
> Cc: pbonzini@redhat.com, qemu-devel@nongnu.org, dietmar@proxmox.com, stefanha@gmail.com
> Inviato: Mercoledì, 3 aprile 2013 7:51:43
> Oggetto: Re: [Qemu-devel] [PATCH 2/3] block: adjust qmp_transaction to be extendable
>
> 于 2013-4-2 21:55, Kevin Wolf 写道:
> > Am 01.04.2013 um 12:01 hat Wenchao Xia geschrieben:
> >> Now code for external snapshot are packaged as one case
> >> in qmp_transaction, so later other operation could be added.
> >> The logic in qmp_transaction is changed a bit: Original code
> >> tries to create all images first and then update all *bdrv
> >> once together, new code create and update one *bdrv one time,
> >> and use bdrv_deappend() to rollback on fail. This allows mixing
> >> different kind of requests in qmp_transaction() later.
> >>
> >> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
> >> ---
> >> blockdev.c | 250
> >> +++++++++++++++++++++++++++++++++++++-----------------------
> >> 1 files changed, 153 insertions(+), 97 deletions(-)
> >>
> >> diff --git a/blockdev.c b/blockdev.c
> >> index 8cdc9ce..75416fb 100644
> >> --- a/blockdev.c
> >> +++ b/blockdev.c
> >> @@ -779,9 +779,155 @@ void qmp_blockdev_snapshot_sync(const char *device,
> >> const char *snapshot_file,
> >>
> >>
> >> /* New and old BlockDriverState structs for group snapshots */
> >> -typedef struct BlkTransactionStates {
> >> +typedef struct BdrvActionOps {
> >> + int (*commit)(BlockdevAction *action, void **p_opaque, Error **errp);
> >> + void (*rollback)(BlockdevAction *action, void *opaque);
> >> + void (*clean)(BlockdevAction *action, void *opaque);
> >> +} BdrvActionOps;
> >
> > You don't really implement the transactional pattern that was used by
> > the original code (and is used elsewhere). It should work like this:
> >
> > 1. Prepare: This stage performs all operations that can fail. They are
> > not made active yet. For example with snapshotting, open a new
> > BlockDriver state, but don't change the backing file chain yet.
> >
> > 2. Commit: Activate the change. This operation can never fail. For this
> > reason, you never have to undo anything done here.
> >
> > 3. Rollback: Basically just free everything that prepare did up to the
> > error.
> >
> > If you do it your way, you get into serious trouble if rollback involves
> > operations that can fail.
> >
> > In the original code, here start the prepare:
>
> That is a clear comment, thanks. I changed the model since expecting
> commit operation may need rollback, if not I am confident to keep
> original model.
> Since bdrv_snapshot_delete() can fail, I guess assertion of its
> success should be used in the rollback later.
No, if bdrv_snapshot_delete() can fail, you need to split it in two
parts: one that can fail, and one that cannot. If you cannot, then
there are two possibilities:
- if the failures are minor and could be repaired with "qemu-img check -r"
(e.g. lost clusters), then this is not optimal but can still be done;
- otherwise, the operation simply cannot be made transactionable.
In the case of qcow2_snapshot_delete, everything except
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
&header_data, sizeof(header_data));
if (ret < 0) {
goto fail;
}
must be in the prepare phase. Everything after "fail" (which right now
is nothing, but it should at least undo the qcow2_alloc_clusters operation)
must be in the rollback phase. Everything in the middle is the commit
phase.
Paolo
>
> >> @@ -806,125 +950,37 @@ void qmp_transaction(BlockdevActionList *dev_list,
> >> Error **errp)
> >> /* We don't do anything in this loop that commits us to the snapshot
> >> */
> >> while (NULL != dev_entry) {
> >> BlockdevAction *dev_info = NULL;
> >> - BlockDriver *proto_drv;
> >> - BlockDriver *drv;
> >> - int flags;
> >> - enum NewImageMode mode;
> >> - const char *new_image_file;
> >> - const char *device;
> >> - const char *format = "qcow2";
> >> -
> >> dev_info = dev_entry->value;
> >> dev_entry = dev_entry->next;
> >>
> >> states = g_malloc0(sizeof(BlkTransactionStates));
> >> QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, states, entry);
> >>
> >> + states->action = dev_info;
> >> switch (dev_info->kind) {
> >> case BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC:
> >> - device = dev_info->blockdev_snapshot_sync->device;
> >> - if (!dev_info->blockdev_snapshot_sync->has_mode) {
> >> - dev_info->blockdev_snapshot_sync->mode =
> >> NEW_IMAGE_MODE_ABSOLUTE_PATHS;
> >> - }
> >> - new_image_file =
> >> dev_info->blockdev_snapshot_sync->snapshot_file;
> >> - if (dev_info->blockdev_snapshot_sync->has_format) {
> >> - format = dev_info->blockdev_snapshot_sync->format;
> >> - }
> >> - mode = dev_info->blockdev_snapshot_sync->mode;
> >> + states->ops = &external_snapshot_ops;
> >> break;
> >> default:
> >> abort();
> >> }
> >>
> >> - drv = bdrv_find_format(format);
> >> - if (!drv) {
> >> - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
> >> - goto delete_and_fail;
> >> - }
> >> -
> >> - states->old_bs = bdrv_find(device);
> >> - if (!states->old_bs) {
> >> - error_set(errp, QERR_DEVICE_NOT_FOUND, device);
> >> - goto delete_and_fail;
> >> - }
> >> -
> >> - if (!bdrv_is_inserted(states->old_bs)) {
> >> - error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
> >> - goto delete_and_fail;
> >> - }
> >> -
> >> - if (bdrv_in_use(states->old_bs)) {
> >> - error_set(errp, QERR_DEVICE_IN_USE, device);
> >> - goto delete_and_fail;
> >> - }
> >> -
> >> - if (!bdrv_is_read_only(states->old_bs)) {
> >> - if (bdrv_flush(states->old_bs)) {
> >> - error_set(errp, QERR_IO_ERROR);
> >> - goto delete_and_fail;
> >> - }
> >> - }
> >> -
> >> - flags = states->old_bs->open_flags;
> >> -
> >> - proto_drv = bdrv_find_protocol(new_image_file);
> >> - if (!proto_drv) {
> >> - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
> >> - goto delete_and_fail;
> >> - }
> >> -
> >> - /* create new image w/backing file */
> >> - if (mode != NEW_IMAGE_MODE_EXISTING) {
> >> - bdrv_img_create(new_image_file, format,
> >> - states->old_bs->filename,
> >> - states->old_bs->drv->format_name,
> >> - NULL, -1, flags, &local_err, false);
> >> - if (error_is_set(&local_err)) {
> >> - error_propagate(errp, local_err);
> >> - goto delete_and_fail;
> >> - }
> >> - }
> >> -
> >> - /* We will manually add the backing_hd field to the bs later */
> >> - states->new_bs = bdrv_new("");
> >> - /* TODO Inherit bs->options or only take explicit options with an
> >> - * extended QMP command? */
> >> - ret = bdrv_open(states->new_bs, new_image_file, NULL,
> >> - flags | BDRV_O_NO_BACKING, drv);
> >> - if (ret != 0) {
> >> - error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file);
> >> + if (states->ops->commit(states->action, &states->opaque, errp)) {
> >> goto delete_and_fail;
> >> }
> >> }
> >
> > The following block is the commit:
> >
> >> -
> >> - /* Now we are going to do the actual pivot. Everything up to this
> >> point
> >> - * is reversible, but we are committed at this point */
> >> - QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) {
> >> - /* This removes our old bs from the bdrv_states, and adds the new
> >> bs */
> >> - bdrv_append(states->new_bs, states->old_bs);
> >> - /* We don't need (or want) to use the transactional
> >> - * bdrv_reopen_multiple() across all the entries at once, because
> >> we
> >> - * don't want to abort all of them if one of them fails the
> >> reopen */
> >> - bdrv_reopen(states->new_bs, states->new_bs->open_flags &
> >> ~BDRV_O_RDWR,
> >> - NULL);
> >> - }
> >> -
> >> /* success */
> >> goto exit;
> >
> > And this is rollback:
> >
> >> delete_and_fail:
> >> - /*
> >> - * failure, and it is all-or-none; abandon each new bs, and keep using
> >> - * the original bs for all images
> >> - */
> >> QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) {
> >> - if (states->new_bs) {
> >> - bdrv_delete(states->new_bs);
> >> - }
> >> + states->ops->rollback(states->action, states->opaque);
> >> }
> >
> > Kevin
> >
>
>
> --
> Best Regards
>
> Wenchao Xia
>
>
next prev parent reply other threads:[~2013-04-03 7:21 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-01 10:01 [Qemu-devel] [PATCH 0/3] block: make qmp_transaction extendable Wenchao Xia
2013-04-01 10:01 ` [Qemu-devel] [PATCH 1/3] block: add function deappend() Wenchao Xia
2013-04-01 10:01 ` [Qemu-devel] [PATCH 2/3] block: adjust qmp_transaction to be extendable Wenchao Xia
2013-04-02 13:55 ` Kevin Wolf
2013-04-03 5:51 ` Wenchao Xia
2013-04-03 7:21 ` Paolo Bonzini [this message]
2013-04-03 9:02 ` Wenchao Xia
2013-04-03 9:17 ` Paolo Bonzini
2013-04-03 9:22 ` Kevin Wolf
2013-04-03 10:33 ` Wenchao Xia
2013-04-17 14:42 ` Stefan Hajnoczi
2013-04-18 3:00 ` Wenchao Xia
2013-04-18 6:35 ` Stefan Hajnoczi
2013-04-01 10:01 ` [Qemu-devel] [PATCH 3/3] block: change rollback sequence in qmp_transaction Wenchao Xia
2013-04-01 15:52 ` Eric Blake
2013-04-02 2:34 ` Wenchao Xia
2013-04-02 13:59 ` Kevin Wolf
2013-04-03 5:35 ` Wenchao Xia
2013-04-03 9:03 ` Kevin Wolf
2013-04-03 10:35 ` Wenchao Xia
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=1466473402.1066275.1364973672613.JavaMail.root@redhat.com \
--to=pbonzini@redhat.com \
--cc=dietmar@proxmox.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@gmail.com \
--cc=xiawenc@linux.vnet.ibm.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.