From: Eric Blake <eblake@redhat.com>
To: Kevin Wolf <kwolf@redhat.com>, qemu-block@nongnu.org
Cc: qemu-devel@nongnu.org, mreitz@redhat.com
Subject: Re: [Qemu-devel] [PATCH 10/10] qcow2: Add image locking
Date: Tue, 22 Dec 2015 15:04:12 -0700 [thread overview]
Message-ID: <5679C8DC.6000400@redhat.com> (raw)
In-Reply-To: <1450802786-20893-11-git-send-email-kwolf@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 7346 bytes --]
On 12/22/2015 09:46 AM, Kevin Wolf wrote:
> People have been keeping destroying their qcow2 images by using
Any of these sound better:
People have kept on destroying
People have been destroying
People keep on destroying
> 'qemu-img snapshot' on images that were in use by a VM. This patch adds
> some image locking that protects them against this mistake.
>
> In order to achieve this, a new compatible header flag is introduced
> that tells that the image is currently in use. It is (almost) always set
> when qcow2 considers the image to be active and in a read-write mode.
> During live migration, the source considers the image active until the
> VM stops on migration completion. The destination considers it active as
> soon as it starts running the VM.
>
> In cases where qemu wasn't shut down cleanly, images may incorrectly
> refuse to open. An option override-lock=on is provided to force opening
> the image (this is the option that qemu-img uses for 'force-unlock' and
> 'check --force').
>
> A few test cases have to be adjusted, either to update error messages,
> to use read-only mode to avoid the check, or to override the lock where
> necessary.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
> diff --git a/block/qcow2.c b/block/qcow2.c
> index 544c124..c07a078 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -307,6 +307,8 @@ int qcow2_mark_corrupt(BlockDriverState *bs)
> BDRVQcow2State *s = bs->opaque;
>
> s->incompatible_features |= QCOW2_INCOMPAT_CORRUPT;
> + s->compatible_features &= ~QCOW2_COMPAT_IN_USE;
> +
So the moment we detect something is wrong, we (attempt to) write the
corrupt bit but promise to do no further writes, so it makes sense that
we can claim we are no longer using the image.
>
> @@ -472,6 +474,11 @@ static QemuOptsList qcow2_runtime_opts = {
> .type = QEMU_OPT_NUMBER,
> .help = "Clean unused cache entries after this time (in seconds)",
> },
> + {
> + .name = BDRV_OPT_OVERRIDE_LOCK,
> + .type = QEMU_OPT_BOOL,
> + .help = "Open the image read-write even if it is locked",
> + },
Missing counterpart documentation in qapi/block-core.json
BlockdevOptionsQcow2.
> + /* Protect against opening the image r/w twice at the same time */
> + if (!bs->read_only && (s->compatible_features & QCOW2_COMPAT_IN_USE)) {
> + /* Shared storage is expected during migration */
> + bool migrating = (flags & BDRV_O_INCOMING);
> +
> + if (!migrating && !s->override_lock) {
> + error_set(errp, ERROR_CLASS_IMAGE_FILE_LOCKED,
> + "Image is already in use");
> + error_append_hint(errp, "This check can be disabled "
> + "with override-lock=on. Caution: Opening an "
> + "image twice can cause corruption!");
Here's where I wondered in 6/10 if it is worth providing additional
information about the current lock owner; and that information would
come from [1]...
> @@ -1164,6 +1193,17 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
> }
> }
>
> + /* Set advisory lock in the header (do this as the final step so that
> + * failure doesn't leave a locked image around) */
> + if (!bs->read_only && !(flags & BDRV_O_INCOMING) && s->qcow_version >= 3) {
> + s->compatible_features |= QCOW2_COMPAT_IN_USE;
> + ret = qcow2_update_header(bs);
This says that we set the advisory bit even when override-lock; the only
purpose of override lock is to allow us to write to the image even if
the bit was already set.
I suppose the other choice would be that override-lock on means that we
don't bother to set the bit at all, leaving us with the qemu 2.5
behavior of not claiming the lock and making it easier to stomp on the
image - perhaps useful for regression testing, but probably not as safe
as a default. So I can agree with how you implemented the override.
> @@ -1272,12 +1321,32 @@ fail:
>
> static void qcow2_reopen_commit(BDRVReopenState *state)
> {
> + /* We can't fail the commit, so if the header update fails, we may end up
> + * not protecting the image even though it is writable now. This is okay,
> + * the lock is a best-effort service to protect the user from shooting
> + * themselves into the foot. */
s/into/in/
> + if (state->bs->read_only && (state->flags & BDRV_O_RDWR)) {
> + BDRVQcow2State *s = state->bs->opaque;
> + s->compatible_features |= QCOW2_COMPAT_IN_USE;
> + (void) qcow2_update_header(state->bs);
> + }
> +
> qcow2_update_options_commit(state->bs, state->opaque);
> g_free(state->opaque);
> }
>
> static void qcow2_reopen_abort(BDRVReopenState *state)
> {
> + /* We can't fail the abort, so if the header update fails, we may end up
> + * not protecting the image any more. This is okay, the lock is a
> + * best-effort service to protect the user from shooting themselves into
s/into/in/
> @@ -1708,6 +1777,16 @@ static int qcow2_inactivate(BlockDriverState *bs)
> qcow2_mark_clean(bs);
> }
>
> + if (!bs->read_only) {
> + s->flags |= BDRV_O_INCOMING;
> + s->compatible_features &= ~QCOW2_COMPAT_IN_USE;
> + ret = qcow2_update_header(bs);
> + if (ret < 0) {
> + result = ret;
> + error_report("Could not update qcow2 header: %s", strerror(-ret));
> + }
> + }
> +
> return result;
> }
>
> +++ b/docs/specs/qcow2.txt
> @@ -96,7 +96,12 @@ in the description of a field.
> marking the image file dirty and postponing
> refcount metadata updates.
>
> - Bits 1-63: Reserved (set to 0)
> + Bit 1: Locking bit. If this bit is set, then the
> + image is supposedly in use by some process and
> + shouldn't be opened read-write by another
> + process.
...[1] I'm wondering if we should add a new optional extension header
here, which records the hostname+pid (and maybe also the argv[0]) of the
process that set this bit.
If this bit is clear, the extension header can be ignored/deleted as
useless (or more likely, rewritten the moment we open the file
read-write because we'll be setting the bit again); if this bit is set
but the extension header is not present, we have no further information
to report beyond "file is locked". But if this bit is set and the
extension header is present, then we can attempt to tell the user more
details about who last claimed to be writing to the file (which may help
the user decide if it really still is in use, or if the lock is left
over in error due to an abrupt exit). That also implies that the act of
setting this bit should also default to adding the new extension header,
populated with useful information.
Overall, I like the direction this series is headed in!
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
next prev parent reply other threads:[~2015-12-22 22:04 UTC|newest]
Thread overview: 99+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-22 16:46 [Qemu-devel] [PATCH 00/10] qcow2: Implement image locking Kevin Wolf
2015-12-22 16:46 ` [Qemu-devel] [PATCH 01/10] qcow2: Write feature table only for v3 images Kevin Wolf
2015-12-22 20:20 ` Eric Blake
2016-01-11 15:20 ` Kevin Wolf
2015-12-22 16:46 ` [Qemu-devel] [PATCH 02/10] qcow2: Write full header on image creation Kevin Wolf
2015-12-22 20:25 ` Eric Blake
2015-12-22 16:46 ` [Qemu-devel] [PATCH 03/10] block: Assert no write requests under BDRV_O_INCOMING Kevin Wolf
2015-12-22 20:27 ` Eric Blake
2015-12-22 16:46 ` [Qemu-devel] [PATCH 04/10] block: Fix error path in bdrv_invalidate_cache() Kevin Wolf
2015-12-22 20:31 ` Eric Blake
2015-12-22 16:46 ` [Qemu-devel] [PATCH 05/10] block: Inactivate BDS when migration completes Kevin Wolf
2015-12-22 20:43 ` Eric Blake
2016-01-05 20:21 ` [Qemu-devel] [Qemu-block] " John Snow
2016-01-13 14:25 ` Kevin Wolf
2016-01-13 16:35 ` Eric Blake
2015-12-22 16:46 ` [Qemu-devel] [PATCH 06/10] qemu-img: Prepare for locked images Kevin Wolf
2015-12-22 16:57 ` Daniel P. Berrange
2015-12-22 17:00 ` Kevin Wolf
2015-12-22 21:06 ` Eric Blake
2016-01-11 15:49 ` Markus Armbruster
2016-01-11 16:05 ` Kevin Wolf
2016-01-12 15:20 ` Markus Armbruster
2016-01-12 17:36 ` Kevin Wolf
2016-01-13 8:44 ` Markus Armbruster
2016-01-13 14:19 ` Kevin Wolf
2016-01-14 13:07 ` Markus Armbruster
2016-01-14 14:19 ` Kevin Wolf
2016-01-11 16:22 ` Kevin Wolf
2015-12-22 21:41 ` Eric Blake
2015-12-22 16:46 ` [Qemu-devel] [PATCH 07/10] qcow2: Implement .bdrv_inactivate Kevin Wolf
2015-12-22 21:17 ` Eric Blake
2016-01-11 15:34 ` Kevin Wolf
2015-12-22 16:46 ` [Qemu-devel] [PATCH 08/10] qcow2: Fix BDRV_O_INCOMING handling in qcow2_invalidate_cache() Kevin Wolf
2015-12-22 21:22 ` Eric Blake
2015-12-22 16:46 ` [Qemu-devel] [PATCH 09/10] qcow2: Make image inaccessible after failed qcow2_invalidate_cache() Kevin Wolf
2015-12-22 21:24 ` Eric Blake
2015-12-22 16:46 ` [Qemu-devel] [PATCH 10/10] qcow2: Add image locking Kevin Wolf
2015-12-22 22:04 ` Eric Blake [this message]
2015-12-23 3:14 ` [Qemu-devel] [PATCH 00/10] qcow2: Implement " Fam Zheng
2015-12-23 7:35 ` [Qemu-devel] [Qemu-block] " Denis V. Lunev
2015-12-23 7:46 ` [Qemu-devel] [PATCH RFC 0/5] generic image locking and crash recovery Denis V. Lunev
2015-12-23 7:46 ` [Qemu-devel] [PATCH 1/5] block: added lock image option and callback Denis V. Lunev
2015-12-23 23:48 ` Eric Blake
2016-01-11 17:31 ` Kevin Wolf
2016-01-11 17:58 ` Daniel P. Berrange
2016-01-11 18:35 ` Kevin Wolf
2016-01-13 8:52 ` Markus Armbruster
2016-01-13 9:12 ` Denis V. Lunev
2016-01-13 9:50 ` Daniel P. Berrange
2016-01-13 9:51 ` Daniel P. Berrange
2016-01-12 5:38 ` Denis V. Lunev
2016-01-12 10:10 ` Kevin Wolf
2016-01-12 11:33 ` Fam Zheng
2016-01-12 12:24 ` Denis V. Lunev
2016-01-12 12:28 ` Kevin Wolf
2016-01-12 13:17 ` Fam Zheng
2016-01-12 13:24 ` Daniel P. Berrange
2016-01-13 0:08 ` Fam Zheng
2016-01-12 15:59 ` Denis V. Lunev
2016-01-13 0:10 ` Fam Zheng
2016-01-13 16:44 ` Eric Blake
2016-01-14 7:23 ` Denis V. Lunev
2015-12-23 7:46 ` [Qemu-devel] [PATCH 2/5] block: implemented bdrv_lock_image for raw file Denis V. Lunev
2015-12-23 12:40 ` Daniel P. Berrange
2015-12-23 7:46 ` [Qemu-devel] [PATCH 3/5] block: added check image option and callback bdrv_is_opened_unclean Denis V. Lunev
2015-12-23 9:09 ` Fam Zheng
2015-12-23 9:14 ` Denis V. Lunev
2015-12-23 7:46 ` [Qemu-devel] [PATCH 4/5] qcow2: implemented bdrv_is_opened_unclean Denis V. Lunev
2016-01-11 17:37 ` Kevin Wolf
2015-12-23 7:46 ` [Qemu-devel] [PATCH 5/5] block/paralels: added paralles implementation for bdrv_is_opened_unclean Denis V. Lunev
2015-12-23 8:09 ` [Qemu-devel] [PATCH RFC 0/5] generic image locking and crash recovery Fam Zheng
2015-12-23 8:36 ` Denis V. Lunev
2015-12-23 10:47 ` [Qemu-devel] [PATCH 00/10] qcow2: Implement image locking Daniel P. Berrange
2015-12-23 12:15 ` [Qemu-devel] [Qemu-block] " Roman Kagan
2015-12-23 12:29 ` Daniel P. Berrange
2015-12-23 12:41 ` Denis V. Lunev
2015-12-23 12:46 ` Daniel P. Berrange
2015-12-23 12:34 ` Daniel P. Berrange
2015-12-23 12:47 ` Denis V. Lunev
2015-12-23 12:56 ` Daniel P. Berrange
2016-01-11 17:14 ` [Qemu-devel] " Kevin Wolf
2016-01-11 17:54 ` Daniel P. Berrange
2016-01-13 8:56 ` Markus Armbruster
2016-01-13 9:11 ` [Qemu-devel] [Qemu-block] " Denis V. Lunev
2015-12-23 23:19 ` [Qemu-devel] " Max Reitz
2015-12-24 5:41 ` [Qemu-devel] [Qemu-block] " Denis V. Lunev
2015-12-24 5:42 ` Denis V. Lunev
2016-01-04 17:02 ` Max Reitz
2016-01-11 16:47 ` Kevin Wolf
2016-01-11 17:56 ` Daniel P. Berrange
2015-12-23 14:57 ` [Qemu-devel] " Vasiliy Tolstov
2015-12-23 15:08 ` [Qemu-devel] [Qemu-block] " Denis V. Lunev
2015-12-23 15:11 ` Vasiliy Tolstov
2016-01-11 16:25 ` Kevin Wolf
2015-12-23 15:09 ` Denis V. Lunev
2015-12-24 5:43 ` Denis V. Lunev
2016-01-11 16:33 ` Kevin Wolf
2016-01-11 16:38 ` Denis V. Lunev
2016-01-14 14:01 ` 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=5679C8DC.6000400@redhat.com \
--to=eblake@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).