diff mbox

[v8,03/26] block: Add BDS.backing_overridden

Message ID 20180205151835.20812-4-mreitz@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Max Reitz Feb. 5, 2018, 3:18 p.m. UTC
If the backing file is overridden, this most probably does change the
guest-visible data of a BDS. Therefore, we will need to consider this in
bdrv_refresh_filename().

Adding a new field to the BDS is not nice, but it is very simple and
exactly keeps track of whether the backing file has been overridden.

This commit adds a FIXME which will be remedied by a follow-up commit.
Until then, the respective piece of code will not result in any behavior
that is worse than what we currently have.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
---
 include/block/block_int.h |  1 +
 block.c                   | 13 +++++++++++++
 block/mirror.c            |  4 ++++
 blockdev.c                | 16 ++++++++++++++++
 4 files changed, 34 insertions(+)

Comments

Kevin Wolf Feb. 22, 2018, 1:39 p.m. UTC | #1
Am 05.02.2018 um 16:18 hat Max Reitz geschrieben:
> If the backing file is overridden, this most probably does change the
> guest-visible data of a BDS. Therefore, we will need to consider this in
> bdrv_refresh_filename().
> 
> Adding a new field to the BDS is not nice, but it is very simple and
> exactly keeps track of whether the backing file has been overridden.

...as long as we manage to actually keep it up to date all the time.

First of all, what I'm missing here (or in fact in the comment in the
code) is a definition what "overridden" really means. "specified by the
user" is kind of vague: You consider the backing file relationship for
snapshot=on as user specified, even though the user wasn't explicit
about this. On the other hand, creating a live snapshot results in a
node that isn't user specified.

Isn't the real question to ask whether the default backing file (taken
from the image header) would result in the same tree? The answer to this
changes after more operations, like qmp_change_backing_file().

Considering that there are so many ways to change the answer, I think
the simplest reliable option isn't a new BDS field that needs to updated
everywhere, but looking at the current value of bs->options and
bs->backing_file and see if they match.

> This commit adds a FIXME which will be remedied by a follow-up commit.
> Until then, the respective piece of code will not result in any behavior
> that is worse than what we currently have.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> Reviewed-by: Alberto Garcia <berto@igalia.com>

Kevin
Max Reitz Feb. 22, 2018, 2:55 p.m. UTC | #2
On 2018-02-22 14:39, Kevin Wolf wrote:
> Am 05.02.2018 um 16:18 hat Max Reitz geschrieben:
>> If the backing file is overridden, this most probably does change the
>> guest-visible data of a BDS. Therefore, we will need to consider this in
>> bdrv_refresh_filename().
>>
>> Adding a new field to the BDS is not nice, but it is very simple and
>> exactly keeps track of whether the backing file has been overridden.
> 
> ...as long as we manage to actually keep it up to date all the time.
> 
> First of all, what I'm missing here (or in fact in the comment in the
> code) is a definition what "overridden" really means. "specified by the
> user" is kind of vague: You consider the backing file relationship for
> snapshot=on as user specified, even though the user wasn't explicit
> about this. On the other hand, creating a live snapshot results in a
> node that isn't user specified.
> 
> Isn't the real question to ask whether the default backing file (taken
> from the image header) would result in the same tree? The answer to this
> changes after more operations, like qmp_change_backing_file().

With you so far.

> Considering that there are so many ways to change the answer, I think
> the simplest reliable option isn't a new BDS field that needs to updated
> everywhere, but looking at the current value of bs->options and
> bs->backing_file and see if they match.

I don't see how that is simple.  First, bs->options does not necessarily
reflect the "current options", those would be bs->full_open_options.
And for generating that, we need a way to determine whether the backing
file has been overridden or not, so whether we need to put the backing
options into it or whether we do not.

(I am right that bs->backing_file is what the image header says, right?
So we need to compare it against something that reflects the runtime state.)

What I could see would be comparing bs->backing_file to
bs->backing->bs->filename.  But this sounds very hacky to me.

One thing the comes to mind is that it can break whenever
bdrv_refresh_filename() is clever.  So you specify
'json:{"driver":"null-co"}' in the image header, and
bdrv_refresh_filename() optimizes that to "null-co://".  Now the
filenames differ even though it's still the original filename.  So this
wouldn't work very well either.

Max

>> This commit adds a FIXME which will be remedied by a follow-up commit.
>> Until then, the respective piece of code will not result in any behavior
>> that is worse than what we currently have.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> Reviewed-by: Alberto Garcia <berto@igalia.com>
> 
> Kevin
>
Kevin Wolf Feb. 22, 2018, 3:12 p.m. UTC | #3
Am 22.02.2018 um 15:55 hat Max Reitz geschrieben:
> On 2018-02-22 14:39, Kevin Wolf wrote:
> > Am 05.02.2018 um 16:18 hat Max Reitz geschrieben:
> >> If the backing file is overridden, this most probably does change the
> >> guest-visible data of a BDS. Therefore, we will need to consider this in
> >> bdrv_refresh_filename().
> >>
> >> Adding a new field to the BDS is not nice, but it is very simple and
> >> exactly keeps track of whether the backing file has been overridden.
> > 
> > ...as long as we manage to actually keep it up to date all the time.
> > 
> > First of all, what I'm missing here (or in fact in the comment in the
> > code) is a definition what "overridden" really means. "specified by the
> > user" is kind of vague: You consider the backing file relationship for
> > snapshot=on as user specified, even though the user wasn't explicit
> > about this. On the other hand, creating a live snapshot results in a
> > node that isn't user specified.
> > 
> > Isn't the real question to ask whether the default backing file (taken
> > from the image header) would result in the same tree? The answer to this
> > changes after more operations, like qmp_change_backing_file().
> 
> With you so far.
> 
> > Considering that there are so many ways to change the answer, I think
> > the simplest reliable option isn't a new BDS field that needs to updated
> > everywhere, but looking at the current value of bs->options and
> > bs->backing_file and see if they match.
> 
> I don't see how that is simple.  First, bs->options does not necessarily
> reflect the "current options", those would be bs->full_open_options.
> And for generating that, we need a way to determine whether the backing
> file has been overridden or not, so whether we need to put the backing
> options into it or whether we do not.

For the purpose of this comparison, we need a set of options that
contains the backing file options unconditionally.

> (I am right that bs->backing_file is what the image header says, right?
> So we need to compare it against something that reflects the runtime state.)

I think so, yes.

> What I could see would be comparing bs->backing_file to
> bs->backing->bs->filename.  But this sounds very hacky to me.
> 
> One thing the comes to mind is that it can break whenever
> bdrv_refresh_filename() is clever.  So you specify
> 'json:{"driver":"null-co"}' in the image header, and
> bdrv_refresh_filename() optimizes that to "null-co://".  Now the
> filenames differ even though it's still the original filename.  So this
> wouldn't work very well either.

On the other hand, the problem with your current approach is that it
results in a JSON filename even if you override the backing file and
specify the same file name as we already have in the image header.

In the future, libvirt is going to manually build the graph, so we will
always have the backing file overridden according to the logic in this
patch. I don't think we want to get JSON filenames for all libvirt
managed VMs, so can we realistically do without any kind of comparison?

Kevin
Max Reitz Feb. 22, 2018, 3:17 p.m. UTC | #4
On 2018-02-22 16:12, Kevin Wolf wrote:
> Am 22.02.2018 um 15:55 hat Max Reitz geschrieben:
>> On 2018-02-22 14:39, Kevin Wolf wrote:
>>> Am 05.02.2018 um 16:18 hat Max Reitz geschrieben:
>>>> If the backing file is overridden, this most probably does change the
>>>> guest-visible data of a BDS. Therefore, we will need to consider this in
>>>> bdrv_refresh_filename().
>>>>
>>>> Adding a new field to the BDS is not nice, but it is very simple and
>>>> exactly keeps track of whether the backing file has been overridden.
>>>
>>> ...as long as we manage to actually keep it up to date all the time.
>>>
>>> First of all, what I'm missing here (or in fact in the comment in the
>>> code) is a definition what "overridden" really means. "specified by the
>>> user" is kind of vague: You consider the backing file relationship for
>>> snapshot=on as user specified, even though the user wasn't explicit
>>> about this. On the other hand, creating a live snapshot results in a
>>> node that isn't user specified.
>>>
>>> Isn't the real question to ask whether the default backing file (taken
>>> from the image header) would result in the same tree? The answer to this
>>> changes after more operations, like qmp_change_backing_file().
>>
>> With you so far.
>>
>>> Considering that there are so many ways to change the answer, I think
>>> the simplest reliable option isn't a new BDS field that needs to updated
>>> everywhere, but looking at the current value of bs->options and
>>> bs->backing_file and see if they match.
>>
>> I don't see how that is simple.  First, bs->options does not necessarily
>> reflect the "current options", those would be bs->full_open_options.
>> And for generating that, we need a way to determine whether the backing
>> file has been overridden or not, so whether we need to put the backing
>> options into it or whether we do not.
> 
> For the purpose of this comparison, we need a set of options that
> contains the backing file options unconditionally.
> 
>> (I am right that bs->backing_file is what the image header says, right?
>> So we need to compare it against something that reflects the runtime state.)
> 
> I think so, yes.
> 
>> What I could see would be comparing bs->backing_file to
>> bs->backing->bs->filename.  But this sounds very hacky to me.
>>
>> One thing the comes to mind is that it can break whenever
>> bdrv_refresh_filename() is clever.  So you specify
>> 'json:{"driver":"null-co"}' in the image header, and
>> bdrv_refresh_filename() optimizes that to "null-co://".  Now the
>> filenames differ even though it's still the original filename.  So this
>> wouldn't work very well either.
> 
> On the other hand, the problem with your current approach is that it
> results in a JSON filename even if you override the backing file and
> specify the same file name as we already have in the image header.

Yes.

> In the future, libvirt is going to manually build the graph, so we will
> always have the backing file overridden according to the logic in this
> patch. I don't think we want to get JSON filenames for all libvirt
> managed VMs, so can we realistically do without any kind of comparison?

libvirt doesn't need to query the filename, though, does it?

In my mind, we wanted to phase out filenames and basically only present
them as convenience/legacy information to users who use qemu directly.

I really don't see the point of burdening qemu with simplifying and
niceifying filenames when you want to use node names for everything anyway.

Max
Kevin Wolf Feb. 22, 2018, 4:21 p.m. UTC | #5
Am 22.02.2018 um 16:17 hat Max Reitz geschrieben:
> On 2018-02-22 16:12, Kevin Wolf wrote:
> > Am 22.02.2018 um 15:55 hat Max Reitz geschrieben:
> >> On 2018-02-22 14:39, Kevin Wolf wrote:
> >>> Am 05.02.2018 um 16:18 hat Max Reitz geschrieben:
> >>>> If the backing file is overridden, this most probably does change the
> >>>> guest-visible data of a BDS. Therefore, we will need to consider this in
> >>>> bdrv_refresh_filename().
> >>>>
> >>>> Adding a new field to the BDS is not nice, but it is very simple and
> >>>> exactly keeps track of whether the backing file has been overridden.
> >>>
> >>> ...as long as we manage to actually keep it up to date all the time.
> >>>
> >>> First of all, what I'm missing here (or in fact in the comment in the
> >>> code) is a definition what "overridden" really means. "specified by the
> >>> user" is kind of vague: You consider the backing file relationship for
> >>> snapshot=on as user specified, even though the user wasn't explicit
> >>> about this. On the other hand, creating a live snapshot results in a
> >>> node that isn't user specified.
> >>>
> >>> Isn't the real question to ask whether the default backing file (taken
> >>> from the image header) would result in the same tree? The answer to this
> >>> changes after more operations, like qmp_change_backing_file().
> >>
> >> With you so far.
> >>
> >>> Considering that there are so many ways to change the answer, I think
> >>> the simplest reliable option isn't a new BDS field that needs to updated
> >>> everywhere, but looking at the current value of bs->options and
> >>> bs->backing_file and see if they match.
> >>
> >> I don't see how that is simple.  First, bs->options does not necessarily
> >> reflect the "current options", those would be bs->full_open_options.
> >> And for generating that, we need a way to determine whether the backing
> >> file has been overridden or not, so whether we need to put the backing
> >> options into it or whether we do not.
> > 
> > For the purpose of this comparison, we need a set of options that
> > contains the backing file options unconditionally.
> > 
> >> (I am right that bs->backing_file is what the image header says, right?
> >> So we need to compare it against something that reflects the runtime state.)
> > 
> > I think so, yes.
> > 
> >> What I could see would be comparing bs->backing_file to
> >> bs->backing->bs->filename.  But this sounds very hacky to me.
> >>
> >> One thing the comes to mind is that it can break whenever
> >> bdrv_refresh_filename() is clever.  So you specify
> >> 'json:{"driver":"null-co"}' in the image header, and
> >> bdrv_refresh_filename() optimizes that to "null-co://".  Now the
> >> filenames differ even though it's still the original filename.  So this
> >> wouldn't work very well either.

So what's the full effect here?

You example says that if you use an overcomplicated way to specify an
image (by using json: instead of an URL), you get back an
overcomplicated filename for the parent image (which includes the
backing file even though it's not really necessary). Sounds fair enough
to me.

Can bad things happen with absolute vs. relative paths?

> > On the other hand, the problem with your current approach is that it
> > results in a JSON filename even if you override the backing file and
> > specify the same file name as we already have in the image header.
> 
> Yes.
> 
> > In the future, libvirt is going to manually build the graph, so we will
> > always have the backing file overridden according to the logic in this
> > patch. I don't think we want to get JSON filenames for all libvirt
> > managed VMs, so can we realistically do without any kind of comparison?
> 
> libvirt doesn't need to query the filename, though, does it?

I know that libvirt uses the output in qemu-img info. And I learnt about
that because they were surprised that json: filenames you get there
can't necessarily be fed to QMP (because they contain only strings).

Other than that, I hope they don't. I suppose the filename can end up in
error messages in logfiles, though.

> In my mind, we wanted to phase out filenames and basically only present
> them as convenience/legacy information to users who use qemu directly.
> 
> I really don't see the point of burdening qemu with simplifying and
> niceifying filenames when you want to use node names for everything
> anyway.

But if you essentially say "filenames are only for those who don't use
advanced features", then why bother with overridden backing files?

There are two problems I have with this patch: The first is that it
introduces additional state that needs to be managed correctly in all
future patches that modify the graph, and the second (and worse one) is
that it fails to manage this state correctly even now.

I mentioned snapshots and change-backing-file that can result in a wrong
bs->backing_overridden, and those were only the obvious first places I
had a look at. Even if you fix them, I wouldn't trust my own review to
find all relevant places. And that's a really bad sign for a design.

This is the most important reason why I'm looking for some method to
derive the flag from already existing state.

Kevin
Max Reitz Feb. 22, 2018, 5:47 p.m. UTC | #6
On 2018-02-22 17:21, Kevin Wolf wrote:
> Am 22.02.2018 um 16:17 hat Max Reitz geschrieben:
>> On 2018-02-22 16:12, Kevin Wolf wrote:
>>> Am 22.02.2018 um 15:55 hat Max Reitz geschrieben:
>>>> On 2018-02-22 14:39, Kevin Wolf wrote:
>>>>> Am 05.02.2018 um 16:18 hat Max Reitz geschrieben:
>>>>>> If the backing file is overridden, this most probably does change the
>>>>>> guest-visible data of a BDS. Therefore, we will need to consider this in
>>>>>> bdrv_refresh_filename().
>>>>>>
>>>>>> Adding a new field to the BDS is not nice, but it is very simple and
>>>>>> exactly keeps track of whether the backing file has been overridden.
>>>>>
>>>>> ...as long as we manage to actually keep it up to date all the time.
>>>>>
>>>>> First of all, what I'm missing here (or in fact in the comment in the
>>>>> code) is a definition what "overridden" really means. "specified by the
>>>>> user" is kind of vague: You consider the backing file relationship for
>>>>> snapshot=on as user specified, even though the user wasn't explicit
>>>>> about this. On the other hand, creating a live snapshot results in a
>>>>> node that isn't user specified.
>>>>>
>>>>> Isn't the real question to ask whether the default backing file (taken
>>>>> from the image header) would result in the same tree? The answer to this
>>>>> changes after more operations, like qmp_change_backing_file().
>>>>
>>>> With you so far.
>>>>
>>>>> Considering that there are so many ways to change the answer, I think
>>>>> the simplest reliable option isn't a new BDS field that needs to updated
>>>>> everywhere, but looking at the current value of bs->options and
>>>>> bs->backing_file and see if they match.
>>>>
>>>> I don't see how that is simple.  First, bs->options does not necessarily
>>>> reflect the "current options", those would be bs->full_open_options.
>>>> And for generating that, we need a way to determine whether the backing
>>>> file has been overridden or not, so whether we need to put the backing
>>>> options into it or whether we do not.
>>>
>>> For the purpose of this comparison, we need a set of options that
>>> contains the backing file options unconditionally.
>>>
>>>> (I am right that bs->backing_file is what the image header says, right?
>>>> So we need to compare it against something that reflects the runtime state.)
>>>
>>> I think so, yes.
>>>
>>>> What I could see would be comparing bs->backing_file to
>>>> bs->backing->bs->filename.  But this sounds very hacky to me.
>>>>
>>>> One thing the comes to mind is that it can break whenever
>>>> bdrv_refresh_filename() is clever.  So you specify
>>>> 'json:{"driver":"null-co"}' in the image header, and
>>>> bdrv_refresh_filename() optimizes that to "null-co://".  Now the
>>>> filenames differ even though it's still the original filename.  So this
>>>> wouldn't work very well either.
> 
> So what's the full effect here?
> 
> You example says that if you use an overcomplicated way to specify an
> image (by using json: instead of an URL), you get back an
> overcomplicated filename for the parent image (which includes the
> backing file even though it's not really necessary). Sounds fair enough
> to me.

OK, but one issue is that you've used an overcomplicated way for the
backing file; but you get an overcomplicated filename for the overlay.

> Can bad things happen with absolute vs. relative paths?

"Can"?  Absolutely.  "Do"?  I don't know? :-)

Another thing are non-unique URLs.  For instance, nbd allows you to
specify "nbd:localhost:10809", but it will generate
"nbd://localhost:10809".  (Same for just "nbd://localhost".)

Or of course the good old "file:foo.qcow2".

>>> On the other hand, the problem with your current approach is that it
>>> results in a JSON filename even if you override the backing file and
>>> specify the same file name as we already have in the image header.
>>
>> Yes.
>>
>>> In the future, libvirt is going to manually build the graph, so we will
>>> always have the backing file overridden according to the logic in this
>>> patch. I don't think we want to get JSON filenames for all libvirt
>>> managed VMs, so can we realistically do without any kind of comparison?
>>
>> libvirt doesn't need to query the filename, though, does it?
> 
> I know that libvirt uses the output in qemu-img info. And I learnt about
> that because they were surprised that json: filenames you get there
> can't necessarily be fed to QMP (because they contain only strings).
> 
> Other than that, I hope they don't. I suppose the filename can end up in
> error messages in logfiles, though.

Fair point.  Although it isn't impossible to decrypt json:{} filenames,
it isn't very nice.

(And I suspect most error messages today actually contain the node name,
which is even less useful than json:{} filenames.)

>> In my mind, we wanted to phase out filenames and basically only present
>> them as convenience/legacy information to users who use qemu directly.
>>
>> I really don't see the point of burdening qemu with simplifying and
>> niceifying filenames when you want to use node names for everything
>> anyway.
> 
> But if you essentially say "filenames are only for those who don't use
> advanced features", then why bother with overridden backing files?

Because giving overcomplicated information is better than giving plainly
wrong information.

If we return a filename, it has to be correct.  Sure, we could just not
return filenames, but even then we would need to have a way of
recognizing when to do that.

But given backwards compatibility and all, I can't imagine a way where
we don't have to deal with the backing file issue in one way or another.

If you want to remove filenames from the internal state and for what
queries return (apart from bs->options for protocol nodes) in 3.0, sign
me up for it.

> There are two problems I have with this patch: The first is that it
> introduces additional state that needs to be managed correctly in all
> future patches that modify the graph, and the second (and worse one) is
> that it fails to manage this state correctly even now.

Well, agreed.  I know there were a couple revisions already where I
fixed things.

But then again, I also seem to remember that I've had a discussion about
what to do here with you before, but it's been so long that I can't
remember the actual content.

> I mentioned snapshots and change-backing-file that can result in a wrong
> bs->backing_overridden, and those were only the obvious first places I
> had a look at. Even if you fix them, I wouldn't trust my own review to
> find all relevant places. And that's a really bad sign for a design.
> 
> This is the most important reason why I'm looking for some method to
> derive the flag from already existing state.

The only things I can say to that are "I agree" and "I've tried before".
 The thing is, I started working on this series in November 2015
(apparently), so I've completely forgotten what exactly it was that I
tried and I only know that my result was "I'll have to add this field".

I concede that result may be wrong, and I myself sure hope so.

So thee two things I see now are:

(1) Compare bs->backing_file against bs->backing->bs->filename.  Seems
basically as error-prone as backing_overridden to me, probably not only
because bdrv_refresh_filename() may change .filename.

(2) Keep backing_overridden; but we'd need a central point for changing
bs->backing, i.e. two functions or one function with a boolean
parameter.  That parameter tells it whether we want to change the
current backing file, independently of the file's metadata, or whether
we want to change the backing file in accordance with the file's
metadata.  In the former case, we'd set backing_overridden, in the
latter, we'd clear it.  This function would then be the only one allowed
to modifiy bs->backing.  The issue here is that maybe it's still not as
simple as it sounds, and it is still possible to have backing_overridden
set even though the backing node is indeed what it would be without the
@backing option specified -- but I personally don't see a simple way to
support this.

(We could strcmp bs->backing_file and bs->backing->bs->filename and if
they match, we clear backing_overridden even though it is supposed to be
set.  But that would mean inconsistent behavior (sometimes you're lucky,
sometimes you aren't), and I don't like that very much.  I actually
prefer consistently undesirable behavior over inconsistently desirable
behavior.)

Max
Max Reitz June 26, 2018, 5:34 p.m. UTC | #7
So, while tackling this once more, this is the current state, in short.

I wanted to add a new field BDS.backing_file_canonical which basically
gets set to bs->backing->bs->filename whenever we know that bs->backing
was opened through bs->backing_file.  That is,
bs->backing_file_canonical would be bs->backing_file, but after going
through the whole hoop of bdrv_open() and bdrv_refresh_filename().

With such a field, we could compare bs->backing->bs->filename against
bs->backing_file_canonical, and thus see whether the backing BDS matches
the image header filename.  I hope this would do the right thing
whenever qemu tries to figure out backing filenames on its own; it will
break, though, when the user just uses some filename and that doesn't
happen to coincide with qemu's generated filenames.

(For instance, if you create a new overlay manually, give it some
backing filename, and that backing filename isn't 1:1 what qemu would
reconstruct; and then you open that file with backing=null, and do a
blockdev-snapshot; then qemu will give you a json:{} filename for the
overlay because due to backing=null, it didn't open the overlay's
backing_file and thus doesn't know how it would look reconstructed.  But
I think that's something we could live with.)

((The only real way to fix this I can imagine is to clone the whole
bdrv_parse_filename()/bdrv_open()/bdrv_refresh_filename()
infrastructure, but just for filenames instead of real BDSs.  Yeah, no,
I won't do that.))

OK, so that was an idea, but now it turns out that bs->backing_file
actually isn't that image header's idea of the backing file.  It appears
to mostly be a clone of bs->backing->bs->filename, but not really.
Honestly, I have no idea what it is, but as a matter of fact, it is
modified by bdrv_backing_attach(), so it will probably usually match
bs->backing->bs->filename (unless there is no bs->backing, in which case
it just retains its old value?).  So it pretty much is completely
useless for any comparison here.

So I suppose I'll rename my BDS.backing_file_canonical attempt to
BDS.auto_backing_file, and this will be what the image header contains
(unless we have opened a BDS from it, in which case it will be that
BDS's filename, so it is canonicalized).

Well, or I could just go with backing_overridden, because honestly that
didn't seem so bad.

Max


PS: Or, we could argue that nobody needs filenames anyway and that
they're just for show and debugging nowadays, so nobody actually needs
backing chain information in them.  May sound a bit stupid, but then
again nobody has ever complained that that's in fact the current state.
Max Reitz June 26, 2018, 6:19 p.m. UTC | #8
On 2018-06-26 19:34, Max Reitz wrote:

[...]

> So I suppose I'll rename my BDS.backing_file_canonical attempt to
> BDS.auto_backing_file, and this will be what the image header contains
> (unless we have opened a BDS from it, in which case it will be that
> BDS's filename, so it is canonicalized).

Update: That seems to go down the drain.  We (stupidly) allow taking a
backing filename from the image header and then enriching it with
options from the command line (so you could take null-co:// from the
image header and then the user could give backing.size.  I won't comment
on how little sense that makes (apart from [1]), but in any case, this
means that "we have opened a BDS from it" is very hard to reliably
recognize, because you need to find out whether the user has given any
strong options for the backing file.  That pretty much brings the
complexity back to backing_overridden, I'd say.

Well, or: Whenever the user has given any backing options, the resulting
BDS is categorized as overridden and the filename is not used as a
canonicalized version of auto_backing_file.

I now pretty much fail to see how any of this is better than
backing_overridden, but whatever.

Max

[1] In fact, it's completely broken, because the user-given backing
options only override the backing filename once the user-given options
contain "file.filename".  So you actually cannot really override
anything unless your new backing file has a protocol driver with a
"filename" option.  Well, you can, but that means creating an own BDS
and then giving a reference to that...
diff mbox

Patch

diff --git a/include/block/block_int.h b/include/block/block_int.h
index 29cafa4236..b5c124fcbd 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -619,6 +619,7 @@  struct BlockDriverState {
     char backing_file[PATH_MAX]; /* if non zero, the image is a diff of
                                     this file image */
     char backing_format[16]; /* if non-zero and backing_file exists */
+    bool backing_overridden; /* backing file has been specified by the user */
 
     QDict *full_open_options;
     char exact_filename[PATH_MAX];
diff --git a/block.c b/block.c
index b84aba2d95..66e37219b9 100644
--- a/block.c
+++ b/block.c
@@ -2268,6 +2268,11 @@  int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
     reference = qdict_get_try_str(parent_options, bdref_key);
     if (reference || qdict_haskey(options, "file.filename")) {
         backing_filename[0] = '\0';
+
+        /* FIXME: Should also be set to true if @options contains other runtime
+         *        options which control the data that is read from the backing
+         *        BDS */
+        bs->backing_overridden = true;
     } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
         QDECREF(options);
         goto free_exit;
@@ -2469,6 +2474,9 @@  static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
         goto out;
     }
 
+    bs_snapshot->backing_overridden = true;
+    bdrv_refresh_filename(bs_snapshot);
+
 out:
     QDECREF(snapshot_options);
     g_free(tmp_filename);
@@ -2599,6 +2607,7 @@  static BlockDriverState *bdrv_open_inherit(const char *filename,
     backing = qdict_get_try_str(options, "backing");
     if (backing && *backing == '\0') {
         flags |= BDRV_O_NO_BACKING;
+        bs->backing_overridden = true;
         qdict_del(options, "backing");
     }
 
@@ -5031,6 +5040,10 @@  void bdrv_refresh_filename(BlockDriverState *bs)
      * refresh those first */
     QLIST_FOREACH(child, &bs->children, next) {
         bdrv_refresh_filename(child->bs);
+
+        if (child->role == &child_backing && child->bs->backing_overridden) {
+            bs->backing_overridden = true;
+        }
     }
 
     if (drv->bdrv_refresh_filename) {
diff --git a/block/mirror.c b/block/mirror.c
index 5a627ba589..aa68531352 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -530,6 +530,10 @@  static void mirror_exit(BlockJob *job, void *opaque)
             error_report_err(local_err);
             data->ret = -EPERM;
         }
+
+        /* The target image's file already has been created with the backing
+         * file we just set, so there is no need to set backing_overridden or
+         * call bdrv_refresh_filename(). */
     }
 
     if (s->to_replace) {
diff --git a/blockdev.c b/blockdev.c
index 8e977eef11..bbe264c3c0 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1795,6 +1795,8 @@  static void external_snapshot_commit(BlkActionState *common)
 {
     ExternalSnapshotState *state =
                              DO_UPCAST(ExternalSnapshotState, common, common);
+    TransactionAction *action = common->action;
+    bool image_was_existing = false;
     AioContext *aio_context;
 
     aio_context = bdrv_get_aio_context(state->old_bs);
@@ -1808,6 +1810,20 @@  static void external_snapshot_commit(BlkActionState *common)
                     NULL);
     }
 
+    if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
+        BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data;
+        if (s->has_mode && s->mode == NEW_IMAGE_MODE_EXISTING) {
+            image_was_existing = true;
+        }
+    } else {
+        image_was_existing = true;
+    }
+
+    if (image_was_existing) {
+        state->new_bs->backing_overridden = true;
+        bdrv_refresh_filename(state->new_bs);
+    }
+
     aio_context_release(aio_context);
 }