diff mbox

[PATCHv6,3/5] fw_cfg: move assert() and linking of fw_cfg device to the machine into instance_init()

Message ID 7d5904ae-e66c-5594-cfff-747578d91f4b@ilande.co.uk
State New
Headers show

Commit Message

Mark Cave-Ayland June 19, 2017, 4:57 p.m. UTC
On 19/06/17 15:28, Eduardo Habkost wrote:

> On Mon, Jun 19, 2017 at 01:59:07PM +0100, Mark Cave-Ayland wrote:
>> In preparation for calling fw_cfg_init1() during realize rather than during
>> init, move the assert() checking for existing fw_cfg devices and the linking
>> of the device to the machine with object_property_add_child() to a new
>> fw_cfg instance_init() function.
>>
>> This guarantees that we will still assert() correctly if more than one fw_cfg
>> device is instantiated by accident.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
>> Tested-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  hw/nvram/fw_cfg.c |   14 ++++++++++----
>>  1 file changed, 10 insertions(+), 4 deletions(-)
>>
>> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
>> index 99bdbc2..af45012 100644
>> --- a/hw/nvram/fw_cfg.c
>> +++ b/hw/nvram/fw_cfg.c
>> @@ -915,10 +915,6 @@ static void fw_cfg_init1(DeviceState *dev)
>>      MachineState *machine = MACHINE(qdev_get_machine());
>>      uint32_t version = FW_CFG_VERSION;
>>  
>> -    assert(!object_resolve_path(FW_CFG_PATH, NULL));
>> -
>> -    object_property_add_child(OBJECT(machine), FW_CFG_NAME, OBJECT(s), NULL);
>> -
>>      qdev_init_nofail(dev);
>>  
>>      fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
>> @@ -1020,6 +1016,15 @@ FWCfgState *fw_cfg_find(void)
>>      return FW_CFG(object_resolve_path(FW_CFG_PATH, NULL));
>>  }
>>  
>> +static void fw_cfg_init(Object *obj)
>> +{
>> +    MachineState *machine = MACHINE(qdev_get_machine());
>> +
>> +    assert(!object_resolve_path(FW_CFG_PATH, NULL));
>> +
>> +    object_property_add_child(OBJECT(machine), FW_CFG_NAME, obj, NULL);
> 
> I don't think this belongs to instance_init.  We must always be
> able to instantiate objects without crashing QEMU or affecting
> QEMU global state.  This patch makes device-list-properties
> crash:
> 
>   $ qemu-system-x86_64 -display none -qmp unix:/tmp/qmp,server,nowait &
>   [1] 2848
>   $ echo 'device-list-properties typename=fw_cfg_mem' | ./scripts/qmp/qmp-shell /tmp/qmp
>   Welcome to the QMP low-level shell!
>   Connected to QEMU 2.9.50
>   
>   qemu-system-x86_64: qemu/hw/nvram/fw_cfg.c:974: fw_cfg_init: Assertion `!object_resolve_path(FW_CFG_PATH, NULL)' failed.
>   (QEMU) Disconnected
>   [1]+  Aborted                 (core dumped) qemu-system-x86_64 -display none -qmp unix:/tmp/qmp,server,nowait
>   $ 
> 
> 
> I suggest moving this check to realize, like the rest of
> fw_cfg_init1(), but change it to do proper error reporting
> instead of asserting.

In that case what do you think is the best way to prevent realization of
a second instance? With some playing I've managed to come up with the
following (partial) diff that seems to work in some simple local tests:




What seems to happen is that calling object_property_add_child() only
succeeds for the first instance and so a simple comparison is enough to
determine that the device already exists at FW_CFG_PATH. Or is this a
fairly terrible (ab)use of the QOM APIs?


ATB,

Mark.

Comments

Laszlo Ersek June 19, 2017, 5:09 p.m. UTC | #1
On 06/19/17 18:57, Mark Cave-Ayland wrote:
> On 19/06/17 15:28, Eduardo Habkost wrote:
> 
>> On Mon, Jun 19, 2017 at 01:59:07PM +0100, Mark Cave-Ayland wrote:
>>> In preparation for calling fw_cfg_init1() during realize rather than during
>>> init, move the assert() checking for existing fw_cfg devices and the linking
>>> of the device to the machine with object_property_add_child() to a new
>>> fw_cfg instance_init() function.
>>>
>>> This guarantees that we will still assert() correctly if more than one fw_cfg
>>> device is instantiated by accident.
>>>
>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
>>> Tested-by: Laszlo Ersek <lersek@redhat.com>
>>> ---
>>>  hw/nvram/fw_cfg.c |   14 ++++++++++----
>>>  1 file changed, 10 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
>>> index 99bdbc2..af45012 100644
>>> --- a/hw/nvram/fw_cfg.c
>>> +++ b/hw/nvram/fw_cfg.c
>>> @@ -915,10 +915,6 @@ static void fw_cfg_init1(DeviceState *dev)
>>>      MachineState *machine = MACHINE(qdev_get_machine());
>>>      uint32_t version = FW_CFG_VERSION;
>>>  
>>> -    assert(!object_resolve_path(FW_CFG_PATH, NULL));
>>> -
>>> -    object_property_add_child(OBJECT(machine), FW_CFG_NAME, OBJECT(s), NULL);
>>> -
>>>      qdev_init_nofail(dev);
>>>  
>>>      fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
>>> @@ -1020,6 +1016,15 @@ FWCfgState *fw_cfg_find(void)
>>>      return FW_CFG(object_resolve_path(FW_CFG_PATH, NULL));
>>>  }
>>>  
>>> +static void fw_cfg_init(Object *obj)
>>> +{
>>> +    MachineState *machine = MACHINE(qdev_get_machine());
>>> +
>>> +    assert(!object_resolve_path(FW_CFG_PATH, NULL));
>>> +
>>> +    object_property_add_child(OBJECT(machine), FW_CFG_NAME, obj, NULL);
>>
>> I don't think this belongs to instance_init.  We must always be
>> able to instantiate objects without crashing QEMU or affecting
>> QEMU global state.  This patch makes device-list-properties
>> crash:
>>
>>   $ qemu-system-x86_64 -display none -qmp unix:/tmp/qmp,server,nowait &
>>   [1] 2848
>>   $ echo 'device-list-properties typename=fw_cfg_mem' | ./scripts/qmp/qmp-shell /tmp/qmp
>>   Welcome to the QMP low-level shell!
>>   Connected to QEMU 2.9.50
>>   
>>   qemu-system-x86_64: qemu/hw/nvram/fw_cfg.c:974: fw_cfg_init: Assertion `!object_resolve_path(FW_CFG_PATH, NULL)' failed.
>>   (QEMU) Disconnected
>>   [1]+  Aborted                 (core dumped) qemu-system-x86_64 -display none -qmp unix:/tmp/qmp,server,nowait
>>   $ 
>>
>>
>> I suggest moving this check to realize, like the rest of
>> fw_cfg_init1(), but change it to do proper error reporting
>> instead of asserting.
> 
> In that case what do you think is the best way to prevent realization of
> a second instance? With some playing I've managed to come up with the
> following (partial) diff that seems to work in some simple local tests:
> 
> 
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index 9b0aaa2..e678ec0 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -862,12 +862,20 @@ static void fw_cfg_machine_ready(struct Notifier
> *n, void *data)
> 
> -static void fw_cfg_common_realize(DeviceState *dev)
> +static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
>  {
>      FWCfgState *s = FW_CFG(dev);
>      MachineState *machine = MACHINE(qdev_get_machine());
>      uint32_t version = FW_CFG_VERSION;
> -
> +    Object *obj;
> +
> +    obj = object_resolve_path(FW_CFG_PATH, NULL);
> +    if (obj != OBJECT(dev)) {
> +        error_setg(errp, "Only one fw_cfg device can be instantiated per "
> +                         "machine");
> +        return;
> +    }
> +
>      fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
>      fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16);
>      fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC,
> (uint16_t)!machine->enable_graphics);
> 
> 
> What seems to happen is that calling object_property_add_child() only
> succeeds for the first instance and so a simple comparison is enough to
> determine that the device already exists at FW_CFG_PATH. Or is this a
> fairly terrible (ab)use of the QOM APIs?

This has jogged my memory about how we ensure "at most one" for the
vmgenid device. Please see:

  vmgenid_realize()    [hw/acpi/vmgenid.c]
    find_vmgenid_dev() [include/hw/acpi/vmgenid.h]

... I was quite silly not to think of this on my own now, despite having
authored commit f92063028a0e ("hw/acpi/vmgenid: prevent more than one
vmgenid device", 2017-03-20) :/

Thanks,
Laszlo
Mark Cave-Ayland June 19, 2017, 6:49 p.m. UTC | #2
On 19/06/17 18:09, Laszlo Ersek wrote:

>> What seems to happen is that calling object_property_add_child() only
>> succeeds for the first instance and so a simple comparison is enough to
>> determine that the device already exists at FW_CFG_PATH. Or is this a
>> fairly terrible (ab)use of the QOM APIs?
> 
> This has jogged my memory about how we ensure "at most one" for the
> vmgenid device. Please see:
> 
>   vmgenid_realize()    [hw/acpi/vmgenid.c]
>     find_vmgenid_dev() [include/hw/acpi/vmgenid.h]
> 
> ... I was quite silly not to think of this on my own now, despite having
> authored commit f92063028a0e ("hw/acpi/vmgenid: prevent more than one
> vmgenid device", 2017-03-20) :/

Right that definitely helps - the following code seems to work correctly
when trying to instantiate a mixture of fw_cfg_io and/or fw_cfg_mem types:

if (!object_resolve_path_type("", TYPE_FW_CFG, NULL)) {
    error_setg(errp, "at most one %s device is permitted", TYPE_FW_CFG);
    return;
}

I've also copied the wording from the above commit to make everything
consistent. Does that seem okay? If so, I'll fold it into a v7 patchset.


ATB,

Mark.
Laszlo Ersek June 19, 2017, 10:43 p.m. UTC | #3
On 06/19/17 20:49, Mark Cave-Ayland wrote:
> On 19/06/17 18:09, Laszlo Ersek wrote:
> 
>>> What seems to happen is that calling object_property_add_child() only
>>> succeeds for the first instance and so a simple comparison is enough to
>>> determine that the device already exists at FW_CFG_PATH. Or is this a
>>> fairly terrible (ab)use of the QOM APIs?
>>
>> This has jogged my memory about how we ensure "at most one" for the
>> vmgenid device. Please see:
>>
>>   vmgenid_realize()    [hw/acpi/vmgenid.c]
>>     find_vmgenid_dev() [include/hw/acpi/vmgenid.h]
>>
>> ... I was quite silly not to think of this on my own now, despite having
>> authored commit f92063028a0e ("hw/acpi/vmgenid: prevent more than one
>> vmgenid device", 2017-03-20) :/
> 
> Right that definitely helps - the following code seems to work correctly
> when trying to instantiate a mixture of fw_cfg_io and/or fw_cfg_mem types:
> 
> if (!object_resolve_path_type("", TYPE_FW_CFG, NULL)) {
>     error_setg(errp, "at most one %s device is permitted", TYPE_FW_CFG);
>     return;
> }
> 
> I've also copied the wording from the above commit to make everything
> consistent. Does that seem okay? If so, I'll fold it into a v7 patchset.

It looks good to me, but please await Eduardo's reply as well.

In particular, it should be confirmed that object_resolve_path_type()
matches instances of *subclasses* as well (as I expect it would). Your
test results confirm that; let's make sure it is intentional behavior.
Eduardo (or someone else on the CC list), can you please comment on that?

Thanks!
Laszlo
Mark Cave-Ayland June 21, 2017, 6:58 a.m. UTC | #4
On 19/06/17 23:43, Laszlo Ersek wrote:

> It looks good to me, but please await Eduardo's reply as well.
> 
> In particular, it should be confirmed that object_resolve_path_type()
> matches instances of *subclasses* as well (as I expect it would). Your
> test results confirm that; let's make sure it is intentional behavior.
> Eduardo (or someone else on the CC list), can you please comment on that?

Thanks Laszlo. Eduardo, can you confirm this is the correct behaviour?

I now have a v7 patchset ready to go (currently hosted at
https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
I've currently left off your Tested-by tag since I'm not sure it's still
valid for less-than-trivial changes - if you're happy for me to re-add
it before I send the v7 patchset to the list, please let me know.


ATB,

Mark.
Laszlo Ersek June 21, 2017, 7:48 a.m. UTC | #5
On 06/21/17 08:58, Mark Cave-Ayland wrote:
> On 19/06/17 23:43, Laszlo Ersek wrote:
> 
>> It looks good to me, but please await Eduardo's reply as well.
>>
>> In particular, it should be confirmed that object_resolve_path_type()
>> matches instances of *subclasses* as well (as I expect it would). Your
>> test results confirm that; let's make sure it is intentional behavior.
>> Eduardo (or someone else on the CC list), can you please comment on that?
> 
> Thanks Laszlo. Eduardo, can you confirm this is the correct behaviour?
> 
> I now have a v7 patchset ready to go (currently hosted at
> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
> I've currently left off your Tested-by tag since I'm not sure it's still
> valid for less-than-trivial changes - if you're happy for me to re-add
> it before I send the v7 patchset to the list, please let me know.

I intend to test v7 when you post it.

Thanks,
Laszlo
Eduardo Habkost June 21, 2017, 11:36 a.m. UTC | #6
On Wed, Jun 21, 2017 at 09:48:16AM +0200, Laszlo Ersek wrote:
> On 06/21/17 08:58, Mark Cave-Ayland wrote:
> > On 19/06/17 23:43, Laszlo Ersek wrote:
> > 
> >> It looks good to me, but please await Eduardo's reply as well.
> >>
> >> In particular, it should be confirmed that object_resolve_path_type()
> >> matches instances of *subclasses* as well (as I expect it would). Your
> >> test results confirm that; let's make sure it is intentional behavior.
> >> Eduardo (or someone else on the CC list), can you please comment on that?
> > 
> > Thanks Laszlo. Eduardo, can you confirm this is the correct behaviour?

Sorry for taking so long to reply.  Yes, it should be the correct
behavior.  It's how it's documented:

"This is similar to object_resolve_path.  However, when looking
for a partial path only matches that implement the given type are
considered.  This restricts the search and avoids spuriously
flagging matches as ambiguous."

(Key part here is "implement the given type").

Approach used by commit f92063028a "hw/acpi/vmgenid: prevent more
than one vmgenid device" looks good to me.

> > 
> > I now have a v7 patchset ready to go (currently hosted at
> > https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
> > I've currently left off your Tested-by tag since I'm not sure it's still
> > valid for less-than-trivial changes - if you're happy for me to re-add
> > it before I send the v7 patchset to the list, please let me know.
> 
> I intend to test v7 when you post it.

I still see the instance_init assert() in that branch (commit
17d75643f880).  Is that correct?
Mark Cave-Ayland June 21, 2017, 12:17 p.m. UTC | #7
On 21/06/17 12:36, Eduardo Habkost wrote:

> On Wed, Jun 21, 2017 at 09:48:16AM +0200, Laszlo Ersek wrote:
>> On 06/21/17 08:58, Mark Cave-Ayland wrote:
>>> On 19/06/17 23:43, Laszlo Ersek wrote:
>>>
>>>> It looks good to me, but please await Eduardo's reply as well.
>>>>
>>>> In particular, it should be confirmed that object_resolve_path_type()
>>>> matches instances of *subclasses* as well (as I expect it would). Your
>>>> test results confirm that; let's make sure it is intentional behavior.
>>>> Eduardo (or someone else on the CC list), can you please comment on that?
>>>
>>> Thanks Laszlo. Eduardo, can you confirm this is the correct behaviour?
> 
> Sorry for taking so long to reply.  Yes, it should be the correct
> behavior.  It's how it's documented:
> 
> "This is similar to object_resolve_path.  However, when looking
> for a partial path only matches that implement the given type are
> considered.  This restricts the search and avoids spuriously
> flagging matches as ambiguous."
> 
> (Key part here is "implement the given type").
> 
> Approach used by commit f92063028a "hw/acpi/vmgenid: prevent more
> than one vmgenid device" looks good to me.

That is great news, thanks for confirming this.

>>>
>>> I now have a v7 patchset ready to go (currently hosted at
>>> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
>>> I've currently left off your Tested-by tag since I'm not sure it's still
>>> valid for less-than-trivial changes - if you're happy for me to re-add
>>> it before I send the v7 patchset to the list, please let me know.
>>
>> I intend to test v7 when you post it.
> 
> I still see the instance_init assert() in that branch (commit
> 17d75643f880).  Is that correct?

Yes that was the intention. In 17d75643f880 both the assert() and
object_property_add_child() are moved into the instance_init() function,
and then in the follow-up commit eddedb5 the assert() is removed from
instance_init() and the object_resolve_path_type() check added into
fw_cfg_init1() as part of its conversion into the
fw_cfg_common_realize() function.

One last question which might avoid a future v8 revision: does the error
handling in eddedb5 for the fw_cfg_*_realize() functions look correct?

The existing check for fw_cfg_file_slots_allocate() uses a local_err
Error variable, whereas I've seen a mixture of callers using both this
approach and using the errp Error variable directly. Is there any reason
to prefer one over the other? Currently I'm also using local_err in
order to keep the fw_cfg_*_realize() functions consistent.


ATB,

Mark.
Eduardo Habkost June 21, 2017, 1:23 p.m. UTC | #8
On Wed, Jun 21, 2017 at 01:17:06PM +0100, Mark Cave-Ayland wrote:
> On 21/06/17 12:36, Eduardo Habkost wrote:
> 
> > On Wed, Jun 21, 2017 at 09:48:16AM +0200, Laszlo Ersek wrote:
> >> On 06/21/17 08:58, Mark Cave-Ayland wrote:
> >>> On 19/06/17 23:43, Laszlo Ersek wrote:
> >>>
> >>>> It looks good to me, but please await Eduardo's reply as well.
> >>>>
> >>>> In particular, it should be confirmed that object_resolve_path_type()
> >>>> matches instances of *subclasses* as well (as I expect it would). Your
> >>>> test results confirm that; let's make sure it is intentional behavior.
> >>>> Eduardo (or someone else on the CC list), can you please comment on that?
> >>>
> >>> Thanks Laszlo. Eduardo, can you confirm this is the correct behaviour?
> > 
> > Sorry for taking so long to reply.  Yes, it should be the correct
> > behavior.  It's how it's documented:
> > 
> > "This is similar to object_resolve_path.  However, when looking
> > for a partial path only matches that implement the given type are
> > considered.  This restricts the search and avoids spuriously
> > flagging matches as ambiguous."
> > 
> > (Key part here is "implement the given type").
> > 
> > Approach used by commit f92063028a "hw/acpi/vmgenid: prevent more
> > than one vmgenid device" looks good to me.
> 
> That is great news, thanks for confirming this.
> 
> >>>
> >>> I now have a v7 patchset ready to go (currently hosted at
> >>> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
> >>> I've currently left off your Tested-by tag since I'm not sure it's still
> >>> valid for less-than-trivial changes - if you're happy for me to re-add
> >>> it before I send the v7 patchset to the list, please let me know.
> >>
> >> I intend to test v7 when you post it.
> > 
> > I still see the instance_init assert() in that branch (commit
> > 17d75643f880).  Is that correct?
> 
> Yes that was the intention. In 17d75643f880 both the assert() and
> object_property_add_child() are moved into the instance_init() function,
> and then in the follow-up commit eddedb5 the assert() is removed from
> instance_init() and the object_resolve_path_type() check added into
> fw_cfg_init1() as part of its conversion into the
> fw_cfg_common_realize() function.

We can't move assert() + linking to instance_init even if it's
just temporary, as it makes device-list-properties crash.

Just linking in instance_init is also a problem, because
instance_init should never affect global QEMU state.

You could move linking to realize as well, but: just like you
already moved sysbus_add_io() calls outside realize, I believe
linking belongs outside realize too.  I need to re-read the
discussion threads to understand the motivation behind that.

> 
> One last question which might avoid a future v8 revision: does the error
> handling in eddedb5 for the fw_cfg_*_realize() functions look correct?

The error handling looks correct to me.

> 
> The existing check for fw_cfg_file_slots_allocate() uses a local_err
> Error variable, whereas I've seen a mixture of callers using both this
> approach and using the errp Error variable directly. Is there any reason
> to prefer one over the other? Currently I'm also using local_err in
> order to keep the fw_cfg_*_realize() functions consistent.

You need a local_err variable if you need to handle/check for
errors before propagating them.

Quoting qapi/error.h:

  Create a new error and pass it to the caller:
      error_setg(errp, "situation normal, all fouled up");

  Call a function and receive an error from it:
      Error *err = NULL;
      foo(arg, &err);
      if (err) {
          handle the error...
      }

  [...]

  Receive an error and pass it on to the caller:
      Error *err = NULL;
      foo(arg, &err);
      if (err) {
          handle the error...
          error_propagate(errp, err);
      }
  where Error **errp is a parameter, by convention the last one.

  Do *not* "optimize" this to
      foo(arg, errp);
      if (*errp) { // WRONG!
          handle the error...
      }
  because errp may be NULL!

  But when all you do with the error is pass it on, please use
      foo(arg, errp);
  for readability.

In fw_cfg_*_realize() you can call fw_cfg_common_realize(dev,
errp) directly, but it won't be a problem if you use local_err
just to keep it consistent with the other error checks in the
function.
Mark Cave-Ayland June 23, 2017, 8:12 a.m. UTC | #9
On 21/06/17 14:23, Eduardo Habkost wrote:

>>>>> I now have a v7 patchset ready to go (currently hosted at
>>>>> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
>>>>> I've currently left off your Tested-by tag since I'm not sure it's still
>>>>> valid for less-than-trivial changes - if you're happy for me to re-add
>>>>> it before I send the v7 patchset to the list, please let me know.
>>>>
>>>> I intend to test v7 when you post it.
>>>
>>> I still see the instance_init assert() in that branch (commit
>>> 17d75643f880).  Is that correct?
>>
>> Yes that was the intention. In 17d75643f880 both the assert() and
>> object_property_add_child() are moved into the instance_init() function,
>> and then in the follow-up commit eddedb5 the assert() is removed from
>> instance_init() and the object_resolve_path_type() check added into
>> fw_cfg_init1() as part of its conversion into the
>> fw_cfg_common_realize() function.
> 
> We can't move assert() + linking to instance_init even if it's
> just temporary, as it makes device-list-properties crash.
> 
> Just linking in instance_init is also a problem, because
> instance_init should never affect global QEMU state.
> 
> You could move linking to realize as well, but: just like you
> already moved sysbus_add_io() calls outside realize, I believe
> linking belongs outside realize too.  I need to re-read the
> discussion threads to understand the motivation behind that.

Ultimately the question we're trying to answer is "has someone
instantiated another fw_cfg device for this machine?" and the way it
works currently is that fw_cfg_init_io() and fw_cfg_init_mem() attach
the fw_cfg device to the /machine object and then check after realize
whether a /machine/fw_cfg device already exists, aborting if it does.

So in the current implementation we're not actually concerned with the
placement of fw_cfg within the model itself, and indeed with a fixed
location in the QOM tree it's already completely wrong. If you take a
look at the QOM tree for the sparc/sparc64/ppc machines you'll see that
they really are very far from reality.

For me the use of object_resolve_path_type() during realize is a good
solution since regardless of the location of the fw_cfg we can always
detect whether we have more than one device instance.

However what seems unappealing about this is that while all existing
users which use fw_cfg_init_io() and fw_cfg_init_mem() are fine, in the
case where I am wiring up the device myself then for my sun4u example
the code looks like this:

dev = qdev_create(NULL, TYPE_FW_CFG_IO);
...
qdev_init_nofail(dev);
memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT,
                            &FW_CFG_IO(dev)->comb_iomem);

Here you can see that the device is active because it is mapped into the
correct IO address space, but notice I have forgotten to link it to the
QOM /machine object myself. Hence I can instantiate and map as many
instances as I like and never trigger the duplicate instance check which
makes the check fairly ineffective.

This makes me think that I'm still misunderstanding something, so I'd be
grateful for any further suggestions.

>> One last question which might avoid a future v8 revision: does the error
>> handling in eddedb5 for the fw_cfg_*_realize() functions look correct?
> 
> The error handling looks correct to me.

Thanks for the review, in that case I will leave it in its current form.


ATB,

Mark.
Eduardo Habkost June 23, 2017, 11:50 a.m. UTC | #10
On Fri, Jun 23, 2017 at 09:12:01AM +0100, Mark Cave-Ayland wrote:
> On 21/06/17 14:23, Eduardo Habkost wrote:
> 
> >>>>> I now have a v7 patchset ready to go (currently hosted at
> >>>>> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
> >>>>> I've currently left off your Tested-by tag since I'm not sure it's still
> >>>>> valid for less-than-trivial changes - if you're happy for me to re-add
> >>>>> it before I send the v7 patchset to the list, please let me know.
> >>>>
> >>>> I intend to test v7 when you post it.
> >>>
> >>> I still see the instance_init assert() in that branch (commit
> >>> 17d75643f880).  Is that correct?
> >>
> >> Yes that was the intention. In 17d75643f880 both the assert() and
> >> object_property_add_child() are moved into the instance_init() function,
> >> and then in the follow-up commit eddedb5 the assert() is removed from
> >> instance_init() and the object_resolve_path_type() check added into
> >> fw_cfg_init1() as part of its conversion into the
> >> fw_cfg_common_realize() function.
> > 
> > We can't move assert() + linking to instance_init even if it's
> > just temporary, as it makes device-list-properties crash.
> > 
> > Just linking in instance_init is also a problem, because
> > instance_init should never affect global QEMU state.
> > 
> > You could move linking to realize as well, but: just like you
> > already moved sysbus_add_io() calls outside realize, I believe
> > linking belongs outside realize too.  I need to re-read the
> > discussion threads to understand the motivation behind that.
> 
> Ultimately the question we're trying to answer is "has someone
> instantiated another fw_cfg device for this machine?" and the way it
> works currently is that fw_cfg_init_io() and fw_cfg_init_mem() attach
> the fw_cfg device to the /machine object and then check after realize
> whether a /machine/fw_cfg device already exists, aborting if it does.
> 
> So in the current implementation we're not actually concerned with the
> placement of fw_cfg within the model itself, and indeed with a fixed
> location in the QOM tree it's already completely wrong. If you take a
> look at the QOM tree for the sparc/sparc64/ppc machines you'll see that
> they really are very far from reality.
> 
> For me the use of object_resolve_path_type() during realize is a good
> solution since regardless of the location of the fw_cfg we can always
> detect whether we have more than one device instance.
> 
> However what seems unappealing about this is that while all existing
> users which use fw_cfg_init_io() and fw_cfg_init_mem() are fine, in the
> case where I am wiring up the device myself then for my sun4u example
> the code looks like this:
> 
> dev = qdev_create(NULL, TYPE_FW_CFG_IO);
> ...
> qdev_init_nofail(dev);
> memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT,
>                             &FW_CFG_IO(dev)->comb_iomem);
> 
> Here you can see that the device is active because it is mapped into the
> correct IO address space, but notice I have forgotten to link it to the
> QOM /machine object myself. Hence I can instantiate and map as many
> instances as I like and never trigger the duplicate instance check which
> makes the check fairly ineffective.

This is a good point, but I have a question about that: will something
break if a machine decides to create two fw_cfg objects and map them to
different addresses?  If it won't break, I see no reason to try to
enforce a single instance in the device code.  If it will break, then a
check in realize is still a hack, but might be a good enough solution.
Laszlo Ersek June 23, 2017, 3:52 p.m. UTC | #11
On 06/23/17 13:50, Eduardo Habkost wrote:
> On Fri, Jun 23, 2017 at 09:12:01AM +0100, Mark Cave-Ayland wrote:
>> On 21/06/17 14:23, Eduardo Habkost wrote:
>>
>>>>>>> I now have a v7 patchset ready to go (currently hosted at
>>>>>>> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
>>>>>>> I've currently left off your Tested-by tag since I'm not sure it's still
>>>>>>> valid for less-than-trivial changes - if you're happy for me to re-add
>>>>>>> it before I send the v7 patchset to the list, please let me know.
>>>>>>
>>>>>> I intend to test v7 when you post it.
>>>>>
>>>>> I still see the instance_init assert() in that branch (commit
>>>>> 17d75643f880).  Is that correct?
>>>>
>>>> Yes that was the intention. In 17d75643f880 both the assert() and
>>>> object_property_add_child() are moved into the instance_init() function,
>>>> and then in the follow-up commit eddedb5 the assert() is removed from
>>>> instance_init() and the object_resolve_path_type() check added into
>>>> fw_cfg_init1() as part of its conversion into the
>>>> fw_cfg_common_realize() function.
>>>
>>> We can't move assert() + linking to instance_init even if it's
>>> just temporary, as it makes device-list-properties crash.
>>>
>>> Just linking in instance_init is also a problem, because
>>> instance_init should never affect global QEMU state.
>>>
>>> You could move linking to realize as well, but: just like you
>>> already moved sysbus_add_io() calls outside realize, I believe
>>> linking belongs outside realize too.  I need to re-read the
>>> discussion threads to understand the motivation behind that.
>>
>> Ultimately the question we're trying to answer is "has someone
>> instantiated another fw_cfg device for this machine?" and the way it
>> works currently is that fw_cfg_init_io() and fw_cfg_init_mem() attach
>> the fw_cfg device to the /machine object and then check after realize
>> whether a /machine/fw_cfg device already exists, aborting if it does.
>>
>> So in the current implementation we're not actually concerned with the
>> placement of fw_cfg within the model itself, and indeed with a fixed
>> location in the QOM tree it's already completely wrong. If you take a
>> look at the QOM tree for the sparc/sparc64/ppc machines you'll see that
>> they really are very far from reality.
>>
>> For me the use of object_resolve_path_type() during realize is a good
>> solution since regardless of the location of the fw_cfg we can always
>> detect whether we have more than one device instance.
>>
>> However what seems unappealing about this is that while all existing
>> users which use fw_cfg_init_io() and fw_cfg_init_mem() are fine, in the
>> case where I am wiring up the device myself then for my sun4u example
>> the code looks like this:
>>
>> dev = qdev_create(NULL, TYPE_FW_CFG_IO);
>> ...
>> qdev_init_nofail(dev);
>> memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT,
>>                             &FW_CFG_IO(dev)->comb_iomem);
>>
>> Here you can see that the device is active because it is mapped into the
>> correct IO address space, but notice I have forgotten to link it to the
>> QOM /machine object myself. Hence I can instantiate and map as many
>> instances as I like and never trigger the duplicate instance check which
>> makes the check fairly ineffective.
> 
> This is a good point, but I have a question about that: will something
> break if a machine decides to create two fw_cfg objects and map them to
> different addresses?  If it won't break, I see no reason to try to
> enforce a single instance in the device code.  If it will break, then a
> check in realize is still a hack, but might be a good enough solution.
> 

(1) For the guest, it makes no sense to encounter two fw_cfg devices.
Also, a lot of the existent code in QEMU assumes at most one fw_cfg
device (for example, there is some related ACPI generation).

(2) Relatedly, the fw_cfg_find() helper function is used quite widely,
and it shouldn't break -- either due to more-than-one device instances,
or due to the one fw_cfg device being linked under a path that is
different from FW_CFG_PATH.

Thanks
Laszlo
Eduardo Habkost June 23, 2017, 4:10 p.m. UTC | #12
On Fri, Jun 23, 2017 at 05:52:03PM +0200, Laszlo Ersek wrote:
> On 06/23/17 13:50, Eduardo Habkost wrote:
> > On Fri, Jun 23, 2017 at 09:12:01AM +0100, Mark Cave-Ayland wrote:
> >> On 21/06/17 14:23, Eduardo Habkost wrote:
> >>
> >>>>>>> I now have a v7 patchset ready to go (currently hosted at
> >>>>>>> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
> >>>>>>> I've currently left off your Tested-by tag since I'm not sure it's still
> >>>>>>> valid for less-than-trivial changes - if you're happy for me to re-add
> >>>>>>> it before I send the v7 patchset to the list, please let me know.
> >>>>>>
> >>>>>> I intend to test v7 when you post it.
> >>>>>
> >>>>> I still see the instance_init assert() in that branch (commit
> >>>>> 17d75643f880).  Is that correct?
> >>>>
> >>>> Yes that was the intention. In 17d75643f880 both the assert() and
> >>>> object_property_add_child() are moved into the instance_init() function,
> >>>> and then in the follow-up commit eddedb5 the assert() is removed from
> >>>> instance_init() and the object_resolve_path_type() check added into
> >>>> fw_cfg_init1() as part of its conversion into the
> >>>> fw_cfg_common_realize() function.
> >>>
> >>> We can't move assert() + linking to instance_init even if it's
> >>> just temporary, as it makes device-list-properties crash.
> >>>
> >>> Just linking in instance_init is also a problem, because
> >>> instance_init should never affect global QEMU state.
> >>>
> >>> You could move linking to realize as well, but: just like you
> >>> already moved sysbus_add_io() calls outside realize, I believe
> >>> linking belongs outside realize too.  I need to re-read the
> >>> discussion threads to understand the motivation behind that.
> >>
> >> Ultimately the question we're trying to answer is "has someone
> >> instantiated another fw_cfg device for this machine?" and the way it
> >> works currently is that fw_cfg_init_io() and fw_cfg_init_mem() attach
> >> the fw_cfg device to the /machine object and then check after realize
> >> whether a /machine/fw_cfg device already exists, aborting if it does.
> >>
> >> So in the current implementation we're not actually concerned with the
> >> placement of fw_cfg within the model itself, and indeed with a fixed
> >> location in the QOM tree it's already completely wrong. If you take a
> >> look at the QOM tree for the sparc/sparc64/ppc machines you'll see that
> >> they really are very far from reality.
> >>
> >> For me the use of object_resolve_path_type() during realize is a good
> >> solution since regardless of the location of the fw_cfg we can always
> >> detect whether we have more than one device instance.
> >>
> >> However what seems unappealing about this is that while all existing
> >> users which use fw_cfg_init_io() and fw_cfg_init_mem() are fine, in the
> >> case where I am wiring up the device myself then for my sun4u example
> >> the code looks like this:
> >>
> >> dev = qdev_create(NULL, TYPE_FW_CFG_IO);
> >> ...
> >> qdev_init_nofail(dev);
> >> memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT,
> >>                             &FW_CFG_IO(dev)->comb_iomem);
> >>
> >> Here you can see that the device is active because it is mapped into the
> >> correct IO address space, but notice I have forgotten to link it to the
> >> QOM /machine object myself. Hence I can instantiate and map as many
> >> instances as I like and never trigger the duplicate instance check which
> >> makes the check fairly ineffective.
> > 
> > This is a good point, but I have a question about that: will something
> > break if a machine decides to create two fw_cfg objects and map them to
> > different addresses?  If it won't break, I see no reason to try to
> > enforce a single instance in the device code.  If it will break, then a
> > check in realize is still a hack, but might be a good enough solution.
> > 
> 
> (1) For the guest, it makes no sense to encounter two fw_cfg devices.
> Also, a lot of the existent code in QEMU assumes at most one fw_cfg
> device (for example, there is some related ACPI generation).

This is an argument for making board code ensure there's only one
device, and possibly for providing a helper that board code can use.
But it doesn't require validation on realize.

> 
> (2) Relatedly, the fw_cfg_find() helper function is used quite widely,
> and it shouldn't break -- either due to more-than-one device instances,
> or due to the one fw_cfg device being linked under a path that is
> different from FW_CFG_PATH.

This is also an argument for providing a helper that ensures
fw_cfg_find() will work, but doesn't require validation on realize.


All that said, I don't have a strong argument against doing it on
realize, except my gut feeling that this is not how qdev was
designed[1].  If doing it on realize is the simplest way to do it, I
won't be the one complaining.

[1] I believe the original intent was to make every single device
    user-creatable and define boards in a declarative way in config
    files.  We are very far from that goal.
Laszlo Ersek June 23, 2017, 4:48 p.m. UTC | #13
On 06/23/17 18:10, Eduardo Habkost wrote:
> On Fri, Jun 23, 2017 at 05:52:03PM +0200, Laszlo Ersek wrote:
>> On 06/23/17 13:50, Eduardo Habkost wrote:
>>> On Fri, Jun 23, 2017 at 09:12:01AM +0100, Mark Cave-Ayland wrote:
>>>> On 21/06/17 14:23, Eduardo Habkost wrote:
>>>>
>>>>>>>>> I now have a v7 patchset ready to go (currently hosted at
>>>>>>>>> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
>>>>>>>>> I've currently left off your Tested-by tag since I'm not sure it's still
>>>>>>>>> valid for less-than-trivial changes - if you're happy for me to re-add
>>>>>>>>> it before I send the v7 patchset to the list, please let me know.
>>>>>>>>
>>>>>>>> I intend to test v7 when you post it.
>>>>>>>
>>>>>>> I still see the instance_init assert() in that branch (commit
>>>>>>> 17d75643f880).  Is that correct?
>>>>>>
>>>>>> Yes that was the intention. In 17d75643f880 both the assert() and
>>>>>> object_property_add_child() are moved into the instance_init() function,
>>>>>> and then in the follow-up commit eddedb5 the assert() is removed from
>>>>>> instance_init() and the object_resolve_path_type() check added into
>>>>>> fw_cfg_init1() as part of its conversion into the
>>>>>> fw_cfg_common_realize() function.
>>>>>
>>>>> We can't move assert() + linking to instance_init even if it's
>>>>> just temporary, as it makes device-list-properties crash.
>>>>>
>>>>> Just linking in instance_init is also a problem, because
>>>>> instance_init should never affect global QEMU state.
>>>>>
>>>>> You could move linking to realize as well, but: just like you
>>>>> already moved sysbus_add_io() calls outside realize, I believe
>>>>> linking belongs outside realize too.  I need to re-read the
>>>>> discussion threads to understand the motivation behind that.
>>>>
>>>> Ultimately the question we're trying to answer is "has someone
>>>> instantiated another fw_cfg device for this machine?" and the way it
>>>> works currently is that fw_cfg_init_io() and fw_cfg_init_mem() attach
>>>> the fw_cfg device to the /machine object and then check after realize
>>>> whether a /machine/fw_cfg device already exists, aborting if it does.
>>>>
>>>> So in the current implementation we're not actually concerned with the
>>>> placement of fw_cfg within the model itself, and indeed with a fixed
>>>> location in the QOM tree it's already completely wrong. If you take a
>>>> look at the QOM tree for the sparc/sparc64/ppc machines you'll see that
>>>> they really are very far from reality.
>>>>
>>>> For me the use of object_resolve_path_type() during realize is a good
>>>> solution since regardless of the location of the fw_cfg we can always
>>>> detect whether we have more than one device instance.
>>>>
>>>> However what seems unappealing about this is that while all existing
>>>> users which use fw_cfg_init_io() and fw_cfg_init_mem() are fine, in the
>>>> case where I am wiring up the device myself then for my sun4u example
>>>> the code looks like this:
>>>>
>>>> dev = qdev_create(NULL, TYPE_FW_CFG_IO);
>>>> ...
>>>> qdev_init_nofail(dev);
>>>> memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT,
>>>>                             &FW_CFG_IO(dev)->comb_iomem);
>>>>
>>>> Here you can see that the device is active because it is mapped into the
>>>> correct IO address space, but notice I have forgotten to link it to the
>>>> QOM /machine object myself. Hence I can instantiate and map as many
>>>> instances as I like and never trigger the duplicate instance check which
>>>> makes the check fairly ineffective.
>>>
>>> This is a good point, but I have a question about that: will something
>>> break if a machine decides to create two fw_cfg objects and map them to
>>> different addresses?  If it won't break, I see no reason to try to
>>> enforce a single instance in the device code.  If it will break, then a
>>> check in realize is still a hack, but might be a good enough solution.
>>>
>>
>> (1) For the guest, it makes no sense to encounter two fw_cfg devices.
>> Also, a lot of the existent code in QEMU assumes at most one fw_cfg
>> device (for example, there is some related ACPI generation).
> 
> This is an argument for making board code ensure there's only one
> device, and possibly for providing a helper that board code can use.
> But it doesn't require validation on realize.
> 
>>
>> (2) Relatedly, the fw_cfg_find() helper function is used quite widely,
>> and it shouldn't break -- either due to more-than-one device instances,
>> or due to the one fw_cfg device being linked under a path that is
>> different from FW_CFG_PATH.
> 
> This is also an argument for providing a helper that ensures
> fw_cfg_find() will work, but doesn't require validation on realize.

I agree.

If you read back the discussion threads under the earlier versions of
this patch set, you'll find that I argued for keeping the unicity stuff
-- and possibly some other stuff -- that currently resides in the
fw_cfg_init1() *helper* function outside of device code (realize or
otherwise).

I didn't disagree with the reorganization of the code, but I suggested
to preserve this stuff in helper functions, which board code could call.
This would clearly place the same burden on Mark's new sun4u board code
-- i.e., that new board code would *also* have to call these helper
function(s). Mark disliked this board requirement (he only wanted to
instantiate the device and be done with it, in board code); and we went
from there.

Really, please go back to the earlier discussion around fw_cfg_init1()
and you'll see my original point (which matches what you just voiced).

> All that said, I don't have a strong argument against doing it on
> realize, except my gut feeling that this is not how qdev was
> designed[1].  If doing it on realize is the simplest way to do it, I
> won't be the one complaining.
> 
> [1] I believe the original intent was to make every single device
>     user-creatable and define boards in a declarative way in config
>     files.  We are very far from that goal.

I'm fine either way, I just wanted to accommodate Mark's preference,
because he seemed to strongly dislike having to call any helper
functions from board code, beyond initing and realizing the device.

This is my recollection of the earlier discussion anyway.

Thanks
Laszlo
Eduardo Habkost June 23, 2017, 6:50 p.m. UTC | #14
On Fri, Jun 23, 2017 at 06:48:40PM +0200, Laszlo Ersek wrote:
> On 06/23/17 18:10, Eduardo Habkost wrote:
> > On Fri, Jun 23, 2017 at 05:52:03PM +0200, Laszlo Ersek wrote:
> >> On 06/23/17 13:50, Eduardo Habkost wrote:
> >>> On Fri, Jun 23, 2017 at 09:12:01AM +0100, Mark Cave-Ayland wrote:
> >>>> On 21/06/17 14:23, Eduardo Habkost wrote:
> >>>>
> >>>>>>>>> I now have a v7 patchset ready to go (currently hosted at
> >>>>>>>>> https://github.com/mcayland/qemu/tree/fwcfg7 for the curious). Laszlo,
> >>>>>>>>> I've currently left off your Tested-by tag since I'm not sure it's still
> >>>>>>>>> valid for less-than-trivial changes - if you're happy for me to re-add
> >>>>>>>>> it before I send the v7 patchset to the list, please let me know.
> >>>>>>>>
> >>>>>>>> I intend to test v7 when you post it.
> >>>>>>>
> >>>>>>> I still see the instance_init assert() in that branch (commit
> >>>>>>> 17d75643f880).  Is that correct?
> >>>>>>
> >>>>>> Yes that was the intention. In 17d75643f880 both the assert() and
> >>>>>> object_property_add_child() are moved into the instance_init() function,
> >>>>>> and then in the follow-up commit eddedb5 the assert() is removed from
> >>>>>> instance_init() and the object_resolve_path_type() check added into
> >>>>>> fw_cfg_init1() as part of its conversion into the
> >>>>>> fw_cfg_common_realize() function.
> >>>>>
> >>>>> We can't move assert() + linking to instance_init even if it's
> >>>>> just temporary, as it makes device-list-properties crash.
> >>>>>
> >>>>> Just linking in instance_init is also a problem, because
> >>>>> instance_init should never affect global QEMU state.
> >>>>>
> >>>>> You could move linking to realize as well, but: just like you
> >>>>> already moved sysbus_add_io() calls outside realize, I believe
> >>>>> linking belongs outside realize too.  I need to re-read the
> >>>>> discussion threads to understand the motivation behind that.
> >>>>
> >>>> Ultimately the question we're trying to answer is "has someone
> >>>> instantiated another fw_cfg device for this machine?" and the way it
> >>>> works currently is that fw_cfg_init_io() and fw_cfg_init_mem() attach
> >>>> the fw_cfg device to the /machine object and then check after realize
> >>>> whether a /machine/fw_cfg device already exists, aborting if it does.
> >>>>
> >>>> So in the current implementation we're not actually concerned with the
> >>>> placement of fw_cfg within the model itself, and indeed with a fixed
> >>>> location in the QOM tree it's already completely wrong. If you take a
> >>>> look at the QOM tree for the sparc/sparc64/ppc machines you'll see that
> >>>> they really are very far from reality.
> >>>>
> >>>> For me the use of object_resolve_path_type() during realize is a good
> >>>> solution since regardless of the location of the fw_cfg we can always
> >>>> detect whether we have more than one device instance.
> >>>>
> >>>> However what seems unappealing about this is that while all existing
> >>>> users which use fw_cfg_init_io() and fw_cfg_init_mem() are fine, in the
> >>>> case where I am wiring up the device myself then for my sun4u example
> >>>> the code looks like this:
> >>>>
> >>>> dev = qdev_create(NULL, TYPE_FW_CFG_IO);
> >>>> ...
> >>>> qdev_init_nofail(dev);
> >>>> memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT,
> >>>>                             &FW_CFG_IO(dev)->comb_iomem);
> >>>>
> >>>> Here you can see that the device is active because it is mapped into the
> >>>> correct IO address space, but notice I have forgotten to link it to the
> >>>> QOM /machine object myself. Hence I can instantiate and map as many
> >>>> instances as I like and never trigger the duplicate instance check which
> >>>> makes the check fairly ineffective.
> >>>
> >>> This is a good point, but I have a question about that: will something
> >>> break if a machine decides to create two fw_cfg objects and map them to
> >>> different addresses?  If it won't break, I see no reason to try to
> >>> enforce a single instance in the device code.  If it will break, then a
> >>> check in realize is still a hack, but might be a good enough solution.
> >>>
> >>
> >> (1) For the guest, it makes no sense to encounter two fw_cfg devices.
> >> Also, a lot of the existent code in QEMU assumes at most one fw_cfg
> >> device (for example, there is some related ACPI generation).
> > 
> > This is an argument for making board code ensure there's only one
> > device, and possibly for providing a helper that board code can use.
> > But it doesn't require validation on realize.
> > 
> >>
> >> (2) Relatedly, the fw_cfg_find() helper function is used quite widely,
> >> and it shouldn't break -- either due to more-than-one device instances,
> >> or due to the one fw_cfg device being linked under a path that is
> >> different from FW_CFG_PATH.
> > 
> > This is also an argument for providing a helper that ensures
> > fw_cfg_find() will work, but doesn't require validation on realize.
> 
> I agree.
> 
> If you read back the discussion threads under the earlier versions of
> this patch set, you'll find that I argued for keeping the unicity stuff
> -- and possibly some other stuff -- that currently resides in the
> fw_cfg_init1() *helper* function outside of device code (realize or
> otherwise).
> 
> I didn't disagree with the reorganization of the code, but I suggested
> to preserve this stuff in helper functions, which board code could call.
> This would clearly place the same burden on Mark's new sun4u board code
> -- i.e., that new board code would *also* have to call these helper
> function(s). Mark disliked this board requirement (he only wanted to
> instantiate the device and be done with it, in board code); and we went
> from there.
> 
> Really, please go back to the earlier discussion around fw_cfg_init1()
> and you'll see my original point (which matches what you just voiced).

Yep.  I was just not sure validation on realize was necessary or
convenient.  It looks like we agree it is just convenient.


> 
> > All that said, I don't have a strong argument against doing it on
> > realize, except my gut feeling that this is not how qdev was
> > designed[1].  If doing it on realize is the simplest way to do it, I
> > won't be the one complaining.
> > 
> > [1] I believe the original intent was to make every single device
> >     user-creatable and define boards in a declarative way in config
> >     files.  We are very far from that goal.
> 
> I'm fine either way, I just wanted to accommodate Mark's preference,
> because he seemed to strongly dislike having to call any helper
> functions from board code, beyond initing and realizing the device.
> 
> This is my recollection of the earlier discussion anyway.

I think we are in agreement, then.  If there are no objections from
others against doing object_property_add_child() on realize, I'm also OK
with that.
Mark Cave-Ayland June 25, 2017, 6:58 p.m. UTC | #15
On 23/06/17 19:50, Eduardo Habkost wrote:

>> Really, please go back to the earlier discussion around fw_cfg_init1()
>> and you'll see my original point (which matches what you just voiced).
> 
> Yep.  I was just not sure validation on realize was necessary or
> convenient.  It looks like we agree it is just convenient.
> 
> 
>>
>>> All that said, I don't have a strong argument against doing it on
>>> realize, except my gut feeling that this is not how qdev was
>>> designed[1].  If doing it on realize is the simplest way to do it, I
>>> won't be the one complaining.
>>>
>>> [1] I believe the original intent was to make every single device
>>>     user-creatable and define boards in a declarative way in config
>>>     files.  We are very far from that goal.
>>
>> I'm fine either way, I just wanted to accommodate Mark's preference,
>> because he seemed to strongly dislike having to call any helper
>> functions from board code, beyond initing and realizing the device.
>>
>> This is my recollection of the earlier discussion anyway.
> 
> I think we are in agreement, then.  If there are no objections from
> others against doing object_property_add_child() on realize, I'm also OK
> with that.

Just to clarify here that my objection wasn't so much about calling
helper functions from board code, it was that as the current patch
exposes the MemoryRegions in TYPE_FW_CFG_IO and TYPE_FW_CFG_MEM then as
per my example where the machine link is omitted then the check becomes
useless.

I can see that device_set_realized() will always set the device parent
to /machine/unattached before calling the realize function if the device
doesn't have a parent. So is it even possible to add the device via
object_property_add_child() to the machine during realize? Or could it
be done by making /machine/fw_cfg an alias to its real location in the
QOM tree at realize time without breaking the object_resolve_path_type()
check?

The other interesting option to explore is that since fw_cfg already has
a machine_ready notifier, the check could be moved there similar to as
done in hw/core/machine.c's error_on_sysbus_device() if the check
shouldn't be present in realize. That still doesn't answer the question
as to how to enforce that the device is correctly linked to the machine
though.


ATB,

Mark.
Eduardo Habkost June 27, 2017, 12:49 a.m. UTC | #16
On Sun, Jun 25, 2017 at 07:58:04PM +0100, Mark Cave-Ayland wrote:
> On 23/06/17 19:50, Eduardo Habkost wrote:
> 
> >> Really, please go back to the earlier discussion around fw_cfg_init1()
> >> and you'll see my original point (which matches what you just voiced).
> > 
> > Yep.  I was just not sure validation on realize was necessary or
> > convenient.  It looks like we agree it is just convenient.
> > 
> > 
> >>
> >>> All that said, I don't have a strong argument against doing it on
> >>> realize, except my gut feeling that this is not how qdev was
> >>> designed[1].  If doing it on realize is the simplest way to do it, I
> >>> won't be the one complaining.
> >>>
> >>> [1] I believe the original intent was to make every single device
> >>>     user-creatable and define boards in a declarative way in config
> >>>     files.  We are very far from that goal.
> >>
> >> I'm fine either way, I just wanted to accommodate Mark's preference,
> >> because he seemed to strongly dislike having to call any helper
> >> functions from board code, beyond initing and realizing the device.
> >>
> >> This is my recollection of the earlier discussion anyway.
> > 
> > I think we are in agreement, then.  If there are no objections from
> > others against doing object_property_add_child() on realize, I'm also OK
> > with that.
> 
> Just to clarify here that my objection wasn't so much about calling
> helper functions from board code, it was that as the current patch
> exposes the MemoryRegions in TYPE_FW_CFG_IO and TYPE_FW_CFG_MEM then as
> per my example where the machine link is omitted then the check becomes
> useless.

I don't understand this part.  When and why would the check become
useless?

> 
> I can see that device_set_realized() will always set the device parent
> to /machine/unattached before calling the realize function if the device
> doesn't have a parent. So is it even possible to add the device via
> object_property_add_child() to the machine during realize? Or could it
> be done by making /machine/fw_cfg an alias to its real location in the
> QOM tree at realize time without breaking the object_resolve_path_type()
> check?

Well, if we can't do object_property_add_child() on ->instance_init()
and doing it on ->realize() would require a more complex solution
involving QOM links, I believe the simplest solution is to provide a
helper function.

> 
> The other interesting option to explore is that since fw_cfg already has
> a machine_ready notifier, the check could be moved there similar to as
> done in hw/core/machine.c's error_on_sysbus_device() if the check
> shouldn't be present in realize. That still doesn't answer the question
> as to how to enforce that the device is correctly linked to the machine
> though.

I think both manually mapping+linking from board code or calling a
helper function from board code would be acceptable.
Mark Cave-Ayland June 28, 2017, 7:09 a.m. UTC | #17
On 27/06/17 01:49, Eduardo Habkost wrote:

> On Sun, Jun 25, 2017 at 07:58:04PM +0100, Mark Cave-Ayland wrote:
>> On 23/06/17 19:50, Eduardo Habkost wrote:
>>
>>>> Really, please go back to the earlier discussion around fw_cfg_init1()
>>>> and you'll see my original point (which matches what you just voiced).
>>>
>>> Yep.  I was just not sure validation on realize was necessary or
>>> convenient.  It looks like we agree it is just convenient.
>>>
>>>
>>>>
>>>>> All that said, I don't have a strong argument against doing it on
>>>>> realize, except my gut feeling that this is not how qdev was
>>>>> designed[1].  If doing it on realize is the simplest way to do it, I
>>>>> won't be the one complaining.
>>>>>
>>>>> [1] I believe the original intent was to make every single device
>>>>>     user-creatable and define boards in a declarative way in config
>>>>>     files.  We are very far from that goal.
>>>>
>>>> I'm fine either way, I just wanted to accommodate Mark's preference,
>>>> because he seemed to strongly dislike having to call any helper
>>>> functions from board code, beyond initing and realizing the device.
>>>>
>>>> This is my recollection of the earlier discussion anyway.
>>>
>>> I think we are in agreement, then.  If there are no objections from
>>> others against doing object_property_add_child() on realize, I'm also OK
>>> with that.
>>
>> Just to clarify here that my objection wasn't so much about calling
>> helper functions from board code, it was that as the current patch
>> exposes the MemoryRegions in TYPE_FW_CFG_IO and TYPE_FW_CFG_MEM then as
>> per my example where the machine link is omitted then the check becomes
>> useless.
> 
> I don't understand this part.  When and why would the check become
> useless?

Well because when using the standard QEMU pattern of
qdev_create()...qdev_init_nofail() it is possible to realize the device
and wire up its MemoryRegions manually as I have done with the sun4u
(i.e. it will respond to accesses) multiple times without calling the
helper function and triggering the check. The ingenious part here is
that only the developers who aren't aware that they have to manually
call the helper function will be the ones who get caught out trying to
instantiate the device multiple times ;)

I'm also aware that with QOM we've got 2 conflicting ideas with fw_cfg:
on the one hand we're saying that QOM hierarchy should at some level
represent the topology of the machine, i.e. for sun4u the fw_cfg device
should appear under the ebus device. whereas at the moment we assume a
fixed path of FW_CFG_PATH.

Based upon this I been thinking along the following lines:

1) Alter fw_cfg_find() to use object_resolve_path_type("", TYPE_FW_CFG,
NULL)

This solves the issue of allowing the QOM tree to best represent the
device topology as it will allow fw_cfg_find() to locate the fw_cfg
device regardless of its location, and hence it can be placed as
appropriate for each machine.

2) Add a check at the top of fw_cfg_common_realize() along the lines of:

if (object_unattached(OBJECT(dev)) {
    error_setg(errp, "%s device must be explicitly added as a child "
               object before realize", TYPE_FW_CFG);
    return;
}

This makes it obvious to the developer that they MUST wire up the fw_cfg
device to the machine before realize, and then if more than one device
is instantiated we can still trigger the existing error from my v7 branch:

if (!object_resolve_path_type("", TYPE_FW_CFG, NULL)) {
    error_setg(errp, "at most one %s device is permitted", TYPE_FW_CFG);
    return;
}

I prefer this method because it is impossible for a developer to
accidentally realize the fw_cfg device without attaching it to the
machine first (i.e. fw_cfg_find() will always succeed if this is the
case if altered as per 1) above) and it can only be realized once. And
following the POLA the device can be wired up using
object_property_add_child() as per the numerous existing examples
throughout the QEMU codebase.

Now the minor issue with 2) is that I can't find an easy way to
determine if the device is unattached at realize time. I've tried
something like this:

if (!object_resolve_path_type("/machine/unattached",
    TYPE_FW_CFG, NULL)) {
   ...
   ...
}

However that doesn't work because as the rules differ between partial
and absolute path resolution, we end up resolving the container itself
as opposed to iterating down through the QOM tree. Is there an existing
solution for this or would I need to come up with something that
iterates over the container children to search for a TYPE_FW_CFG device
myself?


ATB,

Mark.
Igor Mammedov June 28, 2017, 2:12 p.m. UTC | #18
On Wed, 28 Jun 2017 08:09:35 +0100
Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> wrote:

> On 27/06/17 01:49, Eduardo Habkost wrote:
> 
> > On Sun, Jun 25, 2017 at 07:58:04PM +0100, Mark Cave-Ayland wrote:  
> >> On 23/06/17 19:50, Eduardo Habkost wrote:
> >>  
> >>>> Really, please go back to the earlier discussion around fw_cfg_init1()
> >>>> and you'll see my original point (which matches what you just voiced).  
> >>>
> >>> Yep.  I was just not sure validation on realize was necessary or
> >>> convenient.  It looks like we agree it is just convenient.
> >>>
> >>>  
> >>>>  
> >>>>> All that said, I don't have a strong argument against doing it on
> >>>>> realize, except my gut feeling that this is not how qdev was
> >>>>> designed[1].  If doing it on realize is the simplest way to do it, I
> >>>>> won't be the one complaining.
> >>>>>
> >>>>> [1] I believe the original intent was to make every single device
> >>>>>     user-creatable and define boards in a declarative way in config
> >>>>>     files.  We are very far from that goal.  
> >>>>
> >>>> I'm fine either way, I just wanted to accommodate Mark's preference,
> >>>> because he seemed to strongly dislike having to call any helper
> >>>> functions from board code, beyond initing and realizing the device.
> >>>>
> >>>> This is my recollection of the earlier discussion anyway.  
> >>>
> >>> I think we are in agreement, then.  If there are no objections from
> >>> others against doing object_property_add_child() on realize, I'm also OK
> >>> with that.  
> >>
> >> Just to clarify here that my objection wasn't so much about calling
> >> helper functions from board code, it was that as the current patch
> >> exposes the MemoryRegions in TYPE_FW_CFG_IO and TYPE_FW_CFG_MEM then as
> >> per my example where the machine link is omitted then the check becomes
> >> useless.  
> > 
> > I don't understand this part.  When and why would the check become
> > useless?  
> 
> Well because when using the standard QEMU pattern of
> qdev_create()...qdev_init_nofail() it is possible to realize the device
> and wire up its MemoryRegions manually as I have done with the sun4u
> (i.e. it will respond to accesses) multiple times without calling the
> helper function and triggering the check. The ingenious part here is
> that only the developers who aren't aware that they have to manually
> call the helper function will be the ones who get caught out trying to
> instantiate the device multiple times ;)
> 
> I'm also aware that with QOM we've got 2 conflicting ideas with fw_cfg:
> on the one hand we're saying that QOM hierarchy should at some level
> represent the topology of the machine, i.e. for sun4u the fw_cfg device
> should appear under the ebus device. whereas at the moment we assume a
> fixed path of FW_CFG_PATH.
> 
> Based upon this I been thinking along the following lines:
> 
> 1) Alter fw_cfg_find() to use object_resolve_path_type("", TYPE_FW_CFG,
> NULL)
I'd make use of the 3rd argument &ambiguous and assert on it
 
> This solves the issue of allowing the QOM tree to best represent the
> device topology as it will allow fw_cfg_find() to locate the fw_cfg
> device regardless of its location, and hence it can be placed as
> appropriate for each machine.
looks reasonable, that's what we were doing in a bunch of other cases


> 2) Add a check at the top of fw_cfg_common_realize() along the lines of:
> 
> if (object_unattached(OBJECT(dev)) {
>     error_setg(errp, "%s device must be explicitly added as a child "
>                object before realize", TYPE_FW_CFG);
>     return;
> }
that would be never trigger as ancestor's DEVICE.realize() always sets
parent if it wasn't set manually before child's realize is called.

in other words it's guarantied that device has parent by the time
realize() is run by device_set_realized()


> This makes it obvious to the developer that they MUST wire up the fw_cfg
> device to the machine before realize, and then if more than one device
> is instantiated we can still trigger the existing error from my v7 branch:
> 
> if (!object_resolve_path_type("", TYPE_FW_CFG, NULL)) {
>     error_setg(errp, "at most one %s device is permitted", TYPE_FW_CFG);
>     return;
> }
reuse fw_cfg_find() here?

> I prefer this method because it is impossible for a developer to
> accidentally realize the fw_cfg device without attaching it to the
> machine first (i.e. fw_cfg_find() will always succeed if this is the
> case if altered as per 1) above) and it can only be realized once. And
> following the POLA the device can be wired up using
> object_property_add_child() as per the numerous existing examples
> throughout the QEMU codebase.
> 
> Now the minor issue with 2) is that I can't find an easy way to
> determine if the device is unattached at realize time. I've tried
> something like this:
> 
> if (!object_resolve_path_type("/machine/unattached",
>     TYPE_FW_CFG, NULL)) {
>    ...
>    ...
> }
> 
> However that doesn't work because as the rules differ between partial
> and absolute path resolution, we end up resolving the container itself
> as opposed to iterating down through the QOM tree. Is there an existing
> solution for this or would I need to come up with something that
> iterates over the container children to search for a TYPE_FW_CFG device
> myself?
> 
> 
> ATB,
> 
> Mark.
> 
>
Laszlo Ersek June 28, 2017, 2:21 p.m. UTC | #19
On 06/28/17 16:12, Igor Mammedov wrote:
> On Wed, 28 Jun 2017 08:09:35 +0100
> Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> wrote:

>> 1) Alter fw_cfg_find() to use object_resolve_path_type("", TYPE_FW_CFG,
>> NULL)
> I'd make use of the 3rd argument &ambiguous and assert on it

I vaguely recall playing with "ambiguous" in find_vmgenid_dev(), but it
didn't work as I expected (or, it wasn't necessary to use). Not sure
about the details, I only remember that, when calling
object_resolve_path_type() like above, from within a realize function,
the object under realization is already considered existent, so if we're
realizing the second (or later) instance of the class,
object_resolve_path_type() will return NULL (regardless of "ambiguous").
If we're realizing the very first instance, then
object_resolve_path_type() will return non-NULL.

I don't mind "ambiguous" if it can be made work fine, just thought that
I'd add this tidbit.

Thanks,
Laszlo
Igor Mammedov June 28, 2017, 3:31 p.m. UTC | #20
On Wed, 28 Jun 2017 16:21:40 +0200
Laszlo Ersek <lersek@redhat.com> wrote:

> On 06/28/17 16:12, Igor Mammedov wrote:
> > On Wed, 28 Jun 2017 08:09:35 +0100
> > Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> wrote:  
> 
> >> 1) Alter fw_cfg_find() to use object_resolve_path_type("", TYPE_FW_CFG,
> >> NULL)  
> > I'd make use of the 3rd argument &ambiguous and assert on it  
> 
> I vaguely recall playing with "ambiguous" in find_vmgenid_dev(), but it
> didn't work as I expected (or, it wasn't necessary to use). Not sure
> about the details, I only remember that, when calling
> object_resolve_path_type() like above, from within a realize function,
> the object under realization is already considered existent, so if we're
> realizing the second (or later) instance of the class,
> object_resolve_path_type() will return NULL (regardless of "ambiguous").
> If we're realizing the very first instance, then
> object_resolve_path_type() will return non-NULL.
> 
> I don't mind "ambiguous" if it can be made work fine, just thought that
> I'd add this tidbit.


looking at object_resolve_partial_path()

        if (ambiguous && *ambiguous) {                                           
            return NULL;                                                         
        }

might make object_resolve_partial_path() return non NULL if ambiguous is NULL


object_resolve_partial_path(,,, NULL)
p0 - p00 - fw0
    |    |
    |      fw1
    |
     fw2

p00 returns NULL &&  only fw2 is found without knowing at all about p00 failure


> 
> Thanks,
> Laszlo
Mark Cave-Ayland June 29, 2017, 12:12 p.m. UTC | #21
On 28/06/17 15:12, Igor Mammedov wrote:

>>> I don't understand this part.  When and why would the check become
>>> useless?  
>>
>> Well because when using the standard QEMU pattern of
>> qdev_create()...qdev_init_nofail() it is possible to realize the device
>> and wire up its MemoryRegions manually as I have done with the sun4u
>> (i.e. it will respond to accesses) multiple times without calling the
>> helper function and triggering the check. The ingenious part here is
>> that only the developers who aren't aware that they have to manually
>> call the helper function will be the ones who get caught out trying to
>> instantiate the device multiple times ;)
>>
>> I'm also aware that with QOM we've got 2 conflicting ideas with fw_cfg:
>> on the one hand we're saying that QOM hierarchy should at some level
>> represent the topology of the machine, i.e. for sun4u the fw_cfg device
>> should appear under the ebus device. whereas at the moment we assume a
>> fixed path of FW_CFG_PATH.
>>
>> Based upon this I been thinking along the following lines:
>>
>> 1) Alter fw_cfg_find() to use object_resolve_path_type("", TYPE_FW_CFG,
>> NULL)
> I'd make use of the 3rd argument &ambiguous and assert on it

I don't think this is relevant here, as one of the aims of the patchset
is to ensure that only one fw_cfg device is realized, since as Laszlo
points out this is an underlying assumption in the code.

>> This solves the issue of allowing the QOM tree to best represent the
>> device topology as it will allow fw_cfg_find() to locate the fw_cfg
>> device regardless of its location, and hence it can be placed as
>> appropriate for each machine.
> looks reasonable, that's what we were doing in a bunch of other cases

Okay.

>> 2) Add a check at the top of fw_cfg_common_realize() along the lines of:
>>
>> if (object_unattached(OBJECT(dev)) {
>>     error_setg(errp, "%s device must be explicitly added as a child "
>>                object before realize", TYPE_FW_CFG);
>>     return;
>> }
> that would be never trigger as ancestor's DEVICE.realize() always sets
> parent if it wasn't set manually before child's realize is called.
> 
> in other words it's guarantied that device has parent by the time
> realize() is run by device_set_realized()

Yes I understand that, although I may not have made it clear enough that
this is pseudo code (there is no object_unattached() function in QEMU).
If you look below you can see that the criteria I am using to
distinguish whether a device is a child or not is to see whether it
exists underneath /machine/unattached, since as you correctly point out
the parent is already set by the time the device is realized.

>> This makes it obvious to the developer that they MUST wire up the fw_cfg
>> device to the machine before realize, and then if more than one device
>> is instantiated we can still trigger the existing error from my v7 branch:
>>
>> if (!object_resolve_path_type("", TYPE_FW_CFG, NULL)) {
>>     error_setg(errp, "at most one %s device is permitted", TYPE_FW_CFG);
>>     return;
>> }
> reuse fw_cfg_find() here?

Yes that is entirely valid - I've made this change locally.

>> I prefer this method because it is impossible for a developer to
>> accidentally realize the fw_cfg device without attaching it to the
>> machine first (i.e. fw_cfg_find() will always succeed if this is the
>> case if altered as per 1) above) and it can only be realized once. And
>> following the POLA the device can be wired up using
>> object_property_add_child() as per the numerous existing examples
>> throughout the QEMU codebase.
>>
>> Now the minor issue with 2) is that I can't find an easy way to
>> determine if the device is unattached at realize time. I've tried
>> something like this:
>>
>> if (!object_resolve_path_type("/machine/unattached",
>>     TYPE_FW_CFG, NULL)) {
>>    ...
>>    ...
>> }
>>
>> However that doesn't work because as the rules differ between partial
>> and absolute path resolution, we end up resolving the container itself
>> as opposed to iterating down through the QOM tree. Is there an existing
>> solution for this or would I need to come up with something that
>> iterates over the container children to search for a TYPE_FW_CFG device
>> myself?

Actually the visitor function isn't too complicated at all and I have
something working now. Let me tidy up the patchset and if it looks good,
I'll re-post it as a v7.


ATB,

Mark.
diff mbox

Patch

diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 9b0aaa2..e678ec0 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -862,12 +862,20 @@  static void fw_cfg_machine_ready(struct Notifier
*n, void *data)

-static void fw_cfg_common_realize(DeviceState *dev)
+static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
 {
     FWCfgState *s = FW_CFG(dev);
     MachineState *machine = MACHINE(qdev_get_machine());
     uint32_t version = FW_CFG_VERSION;
-
+    Object *obj;
+
+    obj = object_resolve_path(FW_CFG_PATH, NULL);
+    if (obj != OBJECT(dev)) {
+        error_setg(errp, "Only one fw_cfg device can be instantiated per "
+                         "machine");
+        return;
+    }
+
     fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
     fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16);
     fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC,
(uint16_t)!machine->enable_graphics);