qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: Max Reitz <mreitz@redhat.com>, qemu-devel@nongnu.org
Cc: kwolf@redhat.com, qemu-block@nongnu.org
Subject: Re: [PATCH v2 3/6] qemu-img: Add bitmap sub-command
Date: Thu, 30 Apr 2020 10:21:46 -0500	[thread overview]
Message-ID: <9d4769d4-09ea-dced-d4bd-9ceb33044202@redhat.com> (raw)
In-Reply-To: <1dcf85b6-d9e6-b952-537c-791daec34ad9@redhat.com>

On 4/30/20 9:55 AM, Max Reitz wrote:
> On 21.04.20 23:20, Eric Blake wrote:
>> Include actions for --add, --remove, --clear, --enable, --disable, and
>> --merge (note that --clear is a bit of fluff, because the same can be
>> accomplished by removing a bitmap and then adding a new one in its
>> place,
> 
> Well, ideally, all of qemu-img is just fluff because “the same can be
> accomplished by launching qemu and issuing the equivalent QMP commands”. :)
> 
>>         but it matches what QMP commands exist).  Listing is omitted,
>> because it does not require a bitmap name and because it was already
>> possible with 'qemu-img info'.
> 
> Fair enough, although it can be said that qemu-img info’s output is
> qcow2-specific.  It might be nice to have some definitely
> format-independent output.  (But we don’t have persistent bitmaps in
> anything but qcow2 yet (or do we in NBD?), so I don’t expect anyone to
> care much.)

We can add a list subcommand later if it is still desired.  I agree that 
a tabular format:

name          enabled   granularity
bitmap1       false     65536
bitmap2       true      512

in isolation is easier to read than:

     bitmaps:
         [0]:
             flags:
             name: bitmap1
             granularity: 65536
         [1]:
             flags:
                 [0]: auto
             name: bitmap2
             granularity: 512

embedded inside even more information.

> 
>>                                  Merge can work either from another
>> bitmap in the same image, or from a bitmap in a distinct image.
>>
>> While this supports --image-opts for the file being modified, I did
>> not think it worth the extra complexity to support that for the source
>> file in a cross-file bitmap merge.  Likewise, I chose to have --merge
>> only take a single source rather than following the QMP support for
>> multiple merges in one go; in part to simplify the command line, and
>> in part because an offline image can achieve the same effect by
>> multiple qemu-img bitmap --merge calls.  We can enhance that if needed
>> in the future (the same way that 'qemu-img convert' has a mode that
>> concatenates multiple sources into one destination).
>>
>> Upcoming patches will add iotest coverage of these commands while
>> also testing other features.
>>
>> Signed-off-by: Eric Blake <eblake@redhat.com>
>> ---
>>   docs/tools/qemu-img.rst |  24 +++++
>>   qemu-img.c              | 198 ++++++++++++++++++++++++++++++++++++++++
>>   qemu-img-cmds.hx        |   7 ++
>>   3 files changed, 229 insertions(+)
>>
>> diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
>> index 7d08c48d308f..4f3b0e2c9ace 100644
>> --- a/docs/tools/qemu-img.rst
>> +++ b/docs/tools/qemu-img.rst
>> @@ -281,6 +281,30 @@ Command description:
>>     For write tests, by default a buffer filled with zeros is written. This can be
>>     overridden with a pattern byte specified by *PATTERN*.
>>
>> +.. option:: bitmap {--add [-g GRANULARITY] [--disabled] | --remove | --clear | --enable | --disable | --merge SOURCE_BITMAP [-b SOURCE_FILE [-F SOURCE_FMT]]} [--object OBJECTDEF] [--image-opts] [-f FMT] FILENAME BITMAP
> 
> So I can do multiple operations in one roll, but they all use the same
> BITMAP?  Sounds a bit weird.  It actually took me a while to understands
> this, because I thought for sure that each command would take a bitmap
> name.  (And was ready to complain that it looked like they don’t, but,
> well, that’s because they don’t.)

All of the operations take one bitmap name (the final BITMAP). 
Additionally, the --merge operation takes a second bitmap name 
(SOURCE_BITMAP).  None of the other operations need a second bitmap 
name, so only --merge requires an option argument.  As written, the { a 
| b | c } implies that operations are mutually exclusive: you can only 
request one operation per qemu-img invocation.

> 
> Although I suppose some practical example like
> 
> $ qemu-img bitmap --add --merge sbmap --disable foo.qcow2 nbmap
> 
> does make sense.[1]
> 
> 
> Would
> 
> $ qemu-img bitmap --add nbmap --merge nbmap sbmap --enable nbmap \
>        foo.qcow2
> 
> make more sense?

That would be more transactional, and more effort to implement.  My 
argument is that you should instead write:

$ qemu-img bitmap --add foo.qcow2 nbmap
$ qemu-img bitmap --merge sbmap foo.qcow2 nbmap
$ qemu-img bitmap --enable foo.qcow2 nbmap

where I only have to implement one operation per qemu-img.

>    Doesn’t really look like it, because at that point you
> just have to ask why not just call qemu-img bitmap multiple times.
> 
> *shrug*
> 
> 
> [1] However, that leads me to ask:  Why does --add need a --disabled
> option?  Isn’t that equivalent to --add --disable?

The QMP command for add has an optional 'disabled' parameter, which I 
exposed here.  Alternatively, we could indeed NOT expose that parameter 
through qemu-img, but require two separate qemu-img bitmap commands to 
add and then disable things.  Atomicity is not a concern here like it 
was in QMP.  Removing that sugar does simplify things slightly.


>> +static int img_bitmap(int argc, char **argv)
>> +{
>> +    Error *err = NULL;
>> +    int c, ret = -1;
>> +    QemuOpts *opts = NULL;
>> +    const char *fmt = NULL, *src_fmt = NULL, *src_filename = NULL;
>> +    const char *filename, *bitmap;
>> +    BlockBackend *blk = NULL, *src = NULL;
>> +    BlockDriverState *bs = NULL, *src_bs = NULL;
>> +    bool image_opts = false;
>> +    unsigned long granularity = 0;
>> +    bool add = false, remove = false, clear = false;
>> +    bool enable = false, disable = false, add_disabled = false;
>> +    const char *merge = NULL;
> 
> So actually we can’t do one operation multiple times in one roll.

Correct.  At least, not as I wrote it.

> 
>> +
>> +    for (;;) {
>> +        static const struct option long_options[] = {
>> +            {"help", no_argument, 0, 'h'},
>> +            {"object", required_argument, 0, OPTION_OBJECT},
>> +            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
>> +            {"add", no_argument, 0, OPTION_ADD},
>> +            {"remove", no_argument, 0, OPTION_REMOVE},
>> +            {"clear", no_argument, 0, OPTION_CLEAR},
>> +            {"enable", no_argument, 0, OPTION_ENABLE},
>> +            {"disable", no_argument, 0, OPTION_DISABLE},
>> +            {"disabled", no_argument, 0, OPTION_DISABLE},
> 
> So if --disable and --disabled are exactly the same, I really don’t know
> why --disabled even exists.

Logically, '--add --disabled' matches the name of the QMP command with 
its optional 'disabled' parameter, while --disable matches the name of 
the QMP command.  We don't have to have the alias; and in fact, if you 
agree that supporting '--add --disabled' is too much sugar (since we 
don't care about atomicity the way QMP did), then life gets simpler to 
drop --disabled altogether.

>> +    if (add && disable) {
>> +        disable = false;
>> +        add_disabled = true;
>> +    }
>> +    if (add + remove + clear + enable + disable + !!merge != 1) {
>> +        error_report("Need exactly one mode of --add, --remove, --clear, "
>> +                     "--enable, --disable, or --merge");
> 
> Aha.  So you can actually only do a single operation.
> 
> That means the doc shouldn’t use {}, in my opinion, because that to me
> means repetition (thanks to EBNF).  It definitely served to confuse me
> greatly until this point.

In command line syntax, I'm most used to seeing repetition as '...', 
optional as [], and mutually-exclusive choice as {|}.  Yes, that's 
different than EBNF.

> 
> I also don’t see why we would disallow multiple operations in one go.
> The --add --merge combination seems useful to me, and I don’t see a
> problem in implementing it.
> 
> I don’t know why we don’t just create a list of operations to execute,
> based on the order given in the argument list, and then execute them in
> order.  That would even allow multiple --merge operations.

If I understand, you're asking why we can't do:

qemu-img bitmap foo.qcow2 --add b1 --merge sb b1

in one operation.

That changes the syntax entirely, compared to what I implemented.  You'd 
have to have an argument to every option, AND figure out how to specify 
TWO arguments to the --merge option.  Might be doable, but seems hairy.

> 
> If we don’t want that (because we don’t want argument order to matter),
> we could still allow all operations to be done at least once and always
> execute them in the same order, e.g.:
> (1) add
> (2) clear
> (3) merge
> (4) disable
> (5) enable
> (6) remove

I still find it simpler to do exactly one operation per invocation.

> 
>> +        goto out;
>> +    }
>> +    if (granularity && !add) {
>> +        error_report("granularity only supported with --add");
>> +        goto out;
>> +    }
>> +    if (src_fmt && !src_filename) {
>> +        error_report("-F only supported with -b");
>> +        goto out;
>> +    }
>> +    if (src_filename && !merge) {
>> +        error_report("alternate source file only supported with --merge");
> 
> “alternate” sounds strange.  Why not be more precise and call it a
> “Merge bitmap source file” or “File to source merge bitmap from”?

"Merge bitmap source file" sounds fine.

>> +
>> +    if (err) {
>> +        error_reportf_err(err, "Bitmap %s operation failed", bitmap);
> 
> Wouldn’t “Operation on bitmap %s failed” work better?

Yes.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



  reply	other threads:[~2020-04-30 15:28 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-21 21:20 [PATCH v2 0/6] qemu-img: Add convert --bitmaps Eric Blake
2020-04-21 21:20 ` [PATCH v2 1/6] docs: Sort sections on qemu-img subcommand parameters Eric Blake
2020-04-30 12:50   ` Max Reitz
2020-04-21 21:20 ` [PATCH v2 2/6] blockdev: Split off basic bitmap operations for qemu-img Eric Blake
2020-04-30 13:59   ` Max Reitz
2020-04-30 14:50     ` Eric Blake
2020-05-08 11:37       ` Kevin Wolf
2020-05-08 13:48         ` Eric Blake
2020-04-21 21:20 ` [PATCH v2 3/6] qemu-img: Add bitmap sub-command Eric Blake
2020-04-30 14:55   ` Max Reitz
2020-04-30 15:21     ` Eric Blake [this message]
2020-05-04 10:01       ` Max Reitz
2020-05-04 13:28         ` Eric Blake
2020-04-21 21:20 ` [PATCH v2 4/6] qcow2: Expose bitmaps' size during measure Eric Blake
2020-05-04 11:36   ` Max Reitz
2020-05-04 13:44     ` Eric Blake
2020-04-21 21:20 ` [PATCH v2 5/6] qemu-img: Add convert --bitmaps option Eric Blake
2020-05-04 12:14   ` Max Reitz
2020-04-21 21:20 ` [PATCH v2 6/6] iotests: Add test 291 to for qemu-img bitmap coverage Eric Blake
2020-05-04 13:05   ` Max Reitz
2020-05-05 21:22     ` Eric Blake
2020-04-21 22:22 ` [PATCH v2 0/6] qemu-img: Add convert --bitmaps no-reply
2020-04-21 22:49   ` [PATCH] fixup! qemu-img: Add bitmap sub-command Eric Blake

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=9d4769d4-09ea-dced-d4bd-9ceb33044202@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).