All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: qemu-block@nongnu.org, qemu-devel@nongnu.org,
	ehabkost@redhat.com, berrange@redhat.com, pbonzini@redhat.com,
	eblake@redhat.com, mreitz@redhat.com, kwolf@redhat.com,
	den@openvz.org, nshirokovskiy@virtuozzo.com, yur@virtuozzo.com,
	dim@virtuozzo.com, igor@virtuozzo.com, pkrempa@redhat.com,
	libvir-list@redhat.com, stefanha@redhat.com
Subject: Re: [PATCH 5/8] qdev: improve find_device_state() to distinguish simple not found case
Date: Thu, 16 Sep 2021 15:54:39 +0300	[thread overview]
Message-ID: <f276f83d-3e41-5349-ffa1-a4282f6cfd35@virtuozzo.com> (raw)
In-Reply-To: <87r1do7q3p.fsf@dusky.pond.sub.org>

16.09.2021 13:48, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> We'll need this for realizing qdev_find_child() in the next commit.
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>> ---
>>   softmmu/qdev-monitor.c | 48 +++++++++++++++++++++++++++++-------------
>>   1 file changed, 33 insertions(+), 15 deletions(-)
>>
>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>> index 721dec2d82..0117989009 100644
>> --- a/softmmu/qdev-monitor.c
>> +++ b/softmmu/qdev-monitor.c
>> @@ -819,7 +819,12 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
>>       object_unref(OBJECT(dev));
>>   }
>>   
>> -static DeviceState *find_device_state(const char *id, Error **errp)
>> +/*
>> + * Returns: 1 when found, @dev set
>> + *          0 not found, @dev and @errp untouched
>> + *         <0 error, or id is ambiguous, @errp set
>> + */
>> +static int find_device_state(const char *id, DeviceState **dev, Error **errp)
>>   {
>>       Object *obj;
>>   
>> @@ -835,17 +840,16 @@ static DeviceState *find_device_state(const char *id, Error **errp)
>>       }
>>   
>>       if (!obj) {
>> -        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>> -                  "Device '%s' not found", id);
>> -        return NULL;
>> +        return 0;
>>       }
>>   
>>       if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
>>           error_setg(errp, "%s is not a hotpluggable device", id);
>> -        return NULL;
>> +        return -EINVAL;
>>       }
>>   
>> -    return DEVICE(obj);
>> +    *dev = DEVICE(obj);
>> +    return 1;
>>   }
>>   
>>   void qdev_unplug(DeviceState *dev, Error **errp)
>> @@ -894,16 +898,25 @@ void qdev_unplug(DeviceState *dev, Error **errp)
>>   
>>   void qmp_device_del(const char *id, Error **errp)
>>   {
>> -    DeviceState *dev = find_device_state(id, errp);
>> -    if (dev != NULL) {
>> -        if (dev->pending_deleted_event) {
>> -            error_setg(errp, "Device %s is already in the "
>> -                             "process of unplug", id);
>> -            return;
>> +    int ret;
>> +    DeviceState *dev;
>> +
>> +    ret = find_device_state(id, &dev, errp);
>> +    if (ret <= 0) {
>> +        if (ret == 0) {
>> +            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>> +                      "Device '%s' not found", id);
>>           }
>> +        return;
>> +    }
>>   
>> -        qdev_unplug(dev, errp);
>> +    if (dev->pending_deleted_event) {
>> +        error_setg(errp, "Device %s is already in the "
>> +                         "process of unplug", id);
>> +        return;
>>       }
>> +
>> +    qdev_unplug(dev, errp);
>>   }
>>   
>>   void hmp_device_add(Monitor *mon, const QDict *qdict)
>> @@ -925,11 +938,16 @@ void hmp_device_del(Monitor *mon, const QDict *qdict)
>>   
>>   BlockBackend *blk_by_qdev_id(const char *id, Error **errp)
>>   {
>> +    int ret;
>>       DeviceState *dev;
>>       BlockBackend *blk;
>>   
>> -    dev = find_device_state(id, errp);
>> -    if (dev == NULL) {
>> +    ret = find_device_state(id, &dev, errp);
>> +    if (ret <= 0) {
>> +        if (ret == 0) {
>> +            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>> +                      "Device '%s' not found", id);
>> +        }
>>           return NULL;
>>       }
> 
> Awkward.
> 
> Before, find_device_state() either finds something (and returns it) or
> doesn't (and sets @errp).
> 
> Afterward, it can fail to find in two ways, and only one of it sets
> @errp.  The existing callers laboriously fuse the two back together.
> The next commit adds a caller that doesn't.
> 
> Failure modes that need to be handled differently are often the result
> of a function doing too much.  Let's have a closer look at this one
> before the patch:
> 
>      static DeviceState *find_device_state(const char *id, Error **errp)
>      {
>          Object *obj;
> 
>          if (id[0] == '/') {
>              obj = object_resolve_path(id, NULL);
> 
> This interprets @id as a QOM path, and tries to resolve it.
> 
> On failure, @obj becomes NULL.  On success, it points to an object of
> arbitrary type.
> 
>          } else {
>              char *root_path = object_get_canonical_path(qdev_get_peripheral());
>              char *path = g_strdup_printf("%s/%s", root_path, id);
> 
>              g_free(root_path);
>              obj = object_resolve_path_type(path, TYPE_DEVICE, NULL);
>              g_free(path);
> 
> This interprets @id as qdev ID, maps it to a QOM path, and tries to
> resolve it to a TYPE_DEVICE.  Fails when the path doesn't resolve, and
> when it resolves to something that isn't a TYPE_DEVICE.  The latter
> can't happen as long as we put only devices under /machine/peripheral/.
> 
> On failure, @obj becomes NULL.  On success, it points to a TYPE_DEVICE
> object.
> 
>          }
> 
>          if (!obj) {
>              error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>                        "Device '%s' not found", id);
>              return NULL;
>          }
> 
>          if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
>              error_setg(errp, "%s is not a hotpluggable device", id);
>              return NULL;
>          }
> 
> Unclean.
> 
> If we somehow ended up with a non-device /machine/peripheral/foo, then
> find_device_state("foo", errp) would fail the first way, but
> find_device_state("/machine/peripheral/foo", errp) would fail the second
> way.  They should fail the exact same way instead.
> 
>          return DEVICE(obj);
>      }
> 
> Better:
> 
>      static DeviceState *find_device_state(const char *id, Error **errp)
>      {
>          Object *obj;
>          DeviceState *dev;
> 
>          if (id[0] == '/') {
>              obj = object_resolve_path(id, NULL);
>          } else {
>              obj = object_resolve_path_component(qdev_get_peripheral(), id);
>          }
> 
>          if (!obj) {
>              error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>                        "Device '%s' not found", id);
>              return NULL;
>          }
> 
>          dev = (DeviceState *)object_dynamic_cast(obj, TYPE_DEVICE);
>          if (!dev) {
>              error_setg(errp, "%s is not a hotpluggable device", id);
>              return NULL;
>          }
> 
>          return dev;
>      }

Looks simpler)

> 
> I'll post this as a cleanup patch.
> 
> Note that this function does two things, one after the other, namely
> 1. resolve a "qdev ID or qom path" string, and 2. convert to
> TYPE_DEVICE, with error checking.
> 
> Factor out the core of 1. into its own helper resolve_id_or_qom_path(),
> and the next commit can do something like
> 
>      obj = resolve_id_or_qom_path(parent_id);
>      if (!obj) {
>          return 0;
>      }
> 
>      dev = object_dynamic_cast(obj, TYPE_DEVICE);
>      if (!dev) {
>          error_setg(errp, ...);
>          return -EINVAL;
>      }
> 

Thanks for working that out, I'll go this way in v2

-- 
Best regards,
Vladimir


  reply	other threads:[~2021-09-16 12:57 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-02 18:54 [PATCH RFC 0/8] blockdev-replace Vladimir Sementsov-Ogievskiy
2021-08-02 18:54 ` [PATCH 1/8] block-backend: blk_root(): drop const specifier on return type Vladimir Sementsov-Ogievskiy
2021-08-02 18:54 ` [PATCH 2/8] block: add BlockParentClass class Vladimir Sementsov-Ogievskiy
2021-09-16  8:34   ` Markus Armbruster
2021-09-16 10:12     ` Vladimir Sementsov-Ogievskiy
2021-09-20  5:28   ` Markus Armbruster
2021-08-02 18:54 ` [PATCH 3/8] block: realize BlockParentClass for BlockDriverState Vladimir Sementsov-Ogievskiy
2021-08-02 18:54 ` [PATCH 4/8] block/export: realize BlockParentClass functionality Vladimir Sementsov-Ogievskiy
2021-08-02 18:54 ` [PATCH 5/8] qdev: improve find_device_state() to distinguish simple not found case Vladimir Sementsov-Ogievskiy
2021-09-16 10:48   ` Markus Armbruster
2021-09-16 12:54     ` Vladimir Sementsov-Ogievskiy [this message]
2021-08-02 18:54 ` [PATCH 6/8] qdev: realize BlockParentClass Vladimir Sementsov-Ogievskiy
2021-09-20  6:08   ` Markus Armbruster
2021-08-02 18:54 ` [PATCH 7/8] block: improve bdrv_replace_node_noperm() Vladimir Sementsov-Ogievskiy
2021-08-02 18:54 ` [PATCH 8/8] qapi: add blockdev-replace command Vladimir Sementsov-Ogievskiy
2021-09-20  6:44   ` Markus Armbruster
2021-09-20 10:02     ` Vladimir Sementsov-Ogievskiy
2021-09-23 10:09       ` Markus Armbruster
2021-09-23 11:54         ` Vladimir Sementsov-Ogievskiy
2021-09-20 11:25   ` Vladimir Sementsov-Ogievskiy
2021-09-02  9:28 ` [PATCH RFC 0/8] blockdev-replace Vladimir Sementsov-Ogievskiy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f276f83d-3e41-5349-ffa1-a4282f6cfd35@virtuozzo.com \
    --to=vsementsov@virtuozzo.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=den@openvz.org \
    --cc=dim@virtuozzo.com \
    --cc=eblake@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=igor@virtuozzo.com \
    --cc=kwolf@redhat.com \
    --cc=libvir-list@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=nshirokovskiy@virtuozzo.com \
    --cc=pbonzini@redhat.com \
    --cc=pkrempa@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=yur@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.