qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v6 28/42] stream: Deal with filters


From: Kevin Wolf
Subject: Re: [PATCH v6 28/42] stream: Deal with filters
Date: Wed, 11 Dec 2019 16:52:24 +0100
User-agent: Mutt/1.12.1 (2019-06-15)

Am 11.12.2019 um 13:52 hat Max Reitz geschrieben:
> On 16.09.19 11:52, Max Reitz wrote:
> > On 13.09.19 16:16, Kevin Wolf wrote:
> >> Am 09.08.2019 um 18:13 hat Max Reitz geschrieben:
> >>> Because of the recent changes that make the stream job independent of
> >>> the base node and instead track the node above it, we have to split that
> >>> "bottom" node into two cases: The bottom COW node, and the node directly
> >>> above the base node (which may be an R/W filter or the bottom COW node).
> >>>
> >>> Signed-off-by: Max Reitz <address@hidden>
> >>> ---
> >>>  qapi/block-core.json |  4 ++++
> >>>  block/stream.c       | 52 ++++++++++++++++++++++++++++----------------
> >>>  blockdev.c           |  2 +-
> >>>  3 files changed, 38 insertions(+), 20 deletions(-)
> 
> 
> [...]
> 
> >>> +    if (bdrv_freeze_chain(bs, above_base, errp) < 0) {
> >>>          return;
> >>>      }
> >>
> >> Hm... This feels odd. There are two places where stopping to freeze the
> >> chain would make obvious sense: At base, like we originally did; or at
> >> base_overlay, like we (intend to) do since commit c624b015, because we
> >> say that we don't actually mind if the user replaces the base image. I
> >> don't see how stopping at the first filter above base makes sense.
> >>
> >> So should this use bottom_cow_node/base_overlay instead of above_base?
> > 
> > I suppose I thought “Better be safe than sorry”.
> > 
> >> You couldn't use StreamBlockJob.above_base any more then because it
> >> could change, but you also don't really need it anywhere. It's only used
> >> for unfreezing (which would change) and for finding the base (you can
> >> still find bdrv_backing_chain_next(s->base_overlay)). I guess this would
> >> even be a code simplification.
> > 
> > Great, I’ll see to it.
> 
> On second thought (yes, I know, it’s been a couple of months...) I’m not
> so sure.
> 
> If @base is a filter, then bdrv_backing_chain_next(s->base_overlay) will
> not return it.  So then the filter will be dropped, but that probably
> isn’t what the user intended.
> 
> (In fact, the block-stream doc says “When streaming completes the image
> file will have the base file as its backing file.”)

Hm... Okay, let's try an example:

    ... <- backing <- filter1 <- filter2 <- filter3 <- top
                         |         |                    |
                      @base    above_base            @device
                                                   base_overlay


The expected result after the job has completed is:

    ... <- backing <- filter1 <- top

This means that filter1 must not go away until the job has completed. In
other words, we would need to freeze the link between @base and
above_base.

If we use backing_bs(above_base) as we currently do, we wouldn't
necessarily get filter1 as the new backing child of top (as the
documentation promises), but whatever is the backing child of filter2
when the job completes. In other words, documentation and code don't
match currently.

Let's look at a few more examples to see which of the options makes more
sense:

1. Assume we drop filter1 while the stream job is running, i.e. backing
   is now the backing child of filter 2. I think it's obvious that when
   the stream job completes, you want backing to be the new backing
   child of top and not add filter1 back to the chain.

2. If we add filter1b between filter1 and filter2, do we want to drop it
   when the job completes? It's not entirely clear, but there are
   probably cases where keeping it makes sense. The user can always drop
   it manually again, but if we delete a node, some requests will go
   through unfiltered.

3. Imagine we replace filter1 wholesale, for example because a
   concurrently running mirror job performs a storage migration for
   everything up to filter1. Do we then want to reinstate the whole old
   subtree when the stream job completes? Certainly not.

So from this I would probably conclude that the bug is the
documentation, not necessarily in the code.

> So now this gets hairy.  We do want exactly @base as the backing file
> unless the user changed the graph.  But how can we detect that and if it
> hasn’t changed find @base again?
> 
> What this patch did in this version worked because the graph was frozen
> until @above_base.

No, it didn't provide the promised semantics, because "unless the user
changed the graph" isn't part of the documentation. But the promised
semantics are probably not what we want, so it's okay.

> Alternatively, we could store a pointer to @base directly (or its node
> nmae) and then see whether there is some node between s->base_overlay
> and bdrv_backing_chain_next(s->base_overlay) that matches that at the
> end of streaming.
> 
> Well, actually, a pointer won’t work because of course maybe that node
> was deleted and the area is now used for an unrelated node that the user
> doesn’t want as the new backing file.
> 
> The node name could actually work, though.  I mean, if there is some
> node in the immediate backing filter chain of base_overlay with that
> node name after streaming, it does make sense to assume that the user
> wants this to be the backing file; regardless of whether that’s exactly
> the same node as it was at the start of streaming.
> 
> But we now also have to think about what to do when there is no node
> with such a node name.  Should we keep all filters below base_overlay?
> Or should we drop all of them?  I actually think keeping them is the
> safer choice...

Using node names feels completely wrong to me. If we can't keep a
pointer (with a reference) because we want the user to be able to
delete the node, then we certainly can't keep the node name either
because that could refer to an entirely different node when the job
completes.

I don't think it's useful to waste too much thought on how to implement
the behaviour required by the documentation. The requirement seems to be
just wrong.

So in the end, maybe your current code is fine, and the way to address
the "doesn't make obvious sense" part is having a comment that explains
why above_base is where we stop freezing.

Kevin

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]