qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [Qemu-block] [PATCH] block: clarify error message for q


From: John Snow
Subject: Re: [Qemu-devel] [Qemu-block] [PATCH] block: clarify error message for qmp-eject
Date: Wed, 18 May 2016 10:13:46 -0400
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.6.0


On 05/18/2016 02:36 AM, Fam Zheng wrote:
> On Wed, 05/18 07:36, Markus Armbruster wrote:
>> Fam Zheng <address@hidden> writes:
>>
>>> On Tue, 05/17 20:42, John Snow wrote:
>>>> If you use HMP's eject but the CDROM tray is locked, you may get a
>>>> confusing error message informing you that the "tray isn't open."
>>>>
>>>> As this is the point of eject, we can do a little better and help
>>>> clarify that the tray was locked and that it (might) open up later,
>>>> so try again.
>>>>
>>>> It's not ideal, but it makes the semantics of the (legacy) eject
>>>> command more understandable to end users when they try to use it.
>>>>
>>>> Signed-off-by: John Snow <address@hidden>
>>>> ---
>>>>  blockdev.c | 36 +++++++++++++++++++++++++++++-------
>>>>  1 file changed, 29 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/blockdev.c b/blockdev.c
>>>> index 1892b8e..feb8484 100644
>>>> --- a/blockdev.c
>>>> +++ b/blockdev.c
>>>> @@ -2290,16 +2290,26 @@ exit:
>>>>      block_job_txn_unref(block_job_txn);
>>>>  }
>>>>  
>>>> +static int do_open_tray(const char *device, bool has_force, bool force,
>>>> +                        Error **errp);
>>>> +
>>>>  void qmp_eject(const char *device, bool has_force, bool force, Error 
>>>> **errp)
>>>>  {
>>>>      Error *local_err = NULL;
>>>> +    int rc;
>>>>  
>>>> -    qmp_blockdev_open_tray(device, has_force, force, &local_err);
>>>> +    rc = do_open_tray(device, has_force, force, &local_err);
>>>>      if (local_err) {
>>>>          error_propagate(errp, local_err);
>>>>          return;
>>>>      }
>>>>  
>>>> +    if (rc == -EINPROGRESS) {
>>>> +        error_setg(errp, "Device '%s' is locked and force was not 
>>>> specified, "
>>>> +                   "wait for tray to open and try again", device);
>>>> +        return;
>>>> +    }
>>>> +
>>>>      qmp_x_blockdev_remove_medium(device, errp);
>>>>  }
>>>>  
>>>> @@ -2327,8 +2337,8 @@ void qmp_block_passwd(bool has_device, const char 
>>>> *device,
>>>>      aio_context_release(aio_context);
>>>>  }
>>>>  
>>>> -void qmp_blockdev_open_tray(const char *device, bool has_force, bool 
>>>> force,
>>>> -                            Error **errp)
>>>> +static int do_open_tray(const char *device, bool has_force, bool force,
>>>> +                        Error **errp)
>>>
>>> Personally I feel the has_force and force could be merged as one parameter.
>>
>> For qmp_blockdev_open_tray(), the signature is dictated by
>> scripts/qapi-commands.py.  To make has_FOO go away, you need to make the
>> FOO non-optional.
>>
>> You have to duplicate the cumbersome has_FOO, FOO couple in your helper
>> functions only when an absent value (has_FOO=false) has special meaning
> 
> I was only talking about the helper function, but that is more of a personal
> taste thing.
> 

The single solitary reason I didn't squash them for the helper was so
that the git diff looked smaller (The new do_eject is functionally
identical to the old qmp_blockdev_open_tray.)

>> you can't get with any present value.  Not my favorite interface design,
>> by the way.
>>
>> We've discussed two improvements to the QAPI language and generators:
>>
>> * Optional with default: has_FOO goes away, and instead FOO assumes the
>>   default value declared in the schema when it's absent.  Optional
>>   without default stays at it is, i.e. has_FOO tells whether it's
>>   present.
>>
>> * Use null pointer for absent when it can't be a value.
>>
>> If Eric stops flooding me with QAPI patches, I might even get to
>> implement them :)
>>
>>>>  {
>>>>      BlockBackend *blk;
>>>>      bool locked;
>>>> @@ -2341,21 +2351,21 @@ void qmp_blockdev_open_tray(const char *device, 
>>>> bool has_force, bool force,
>>>>      if (!blk) {
>>>>          error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>>>                    "Device '%s' not found", device);
>>>> -        return;
>>>> +        return -ENODEV;
>>>>      }
>>>>  
>>>>      if (!blk_dev_has_removable_media(blk)) {
>>>>          error_setg(errp, "Device '%s' is not removable", device);
>>>> -        return;
>>>> +        return -ENOTSUP;
>>>>      }
>>>>  
>>>>      if (!blk_dev_has_tray(blk)) {
>>>>          /* Ignore this command on tray-less devices */
>>>> -        return;
>>>> +        return -ENOSYS;
>>>
>>> I'm not sure how acceptable it is to leave errp untouched while setting ret
>>> code to non-zero. Markus?
>>
>> It's questionable style, becaue it gives the two plausible ways to check
>> for errors different meaning:
>>
>>     if (do_open_tray(...) < 0) ...
>>
>> and
>>
>>     Error *err = NULL;
>>     do_open_tray(..., &err);
>>     if (err) ...
>>
>> I find this confusing.
>>
>> The former way lets me pass a null Error * argument, which is convenient
>> when I'm not interested in error details.
>>
>> Whenever practical, separate an Error-setting function's values into
>> distinct error and success sets.  Example: when a function looks up
>> something, return pointer to it on success, set error and return null on
>> failure.
>>
>> This isn't always practical, for instance, when a pointer-valued
>> function can legitimately return null.  That causes confusion, too.  We
>> fixed a few bugs around such functions.
>>
>> Whether it isn't practical for *this* function I can't say without
>> developing a better understanding of its purpose and context.
> 
> We have this question because errp is mostly human oriented, whereas return
> codes are also used for control logic. From an error pointer a caller can only
> tell if the called function succeeded or not, but cannot tell which type the
> failure is.  Comparing this to exception handling systems in other OO 
> languages
> such as Python, I feel this is because lacking of the type information which
> would cover this case if we had one too.  With error type information, the
> idiom with "ret code + errp" would then become similar to:
> 
>     try:
>         do_open_tray()
>     except EjectInProgress:
>         pass
>     except Exception:
>         # report error
>         ...
> 
> And a return code is not needed. (not saying this is the only type of control
> flow, Functions looking up something will still return pointers, but on the
> other hand it's possible those function may want to return error type too.)
> 
> We used to have rich type errors, which has been abandoned, but I think it
> probably makes some sense to let Error carry a standard error code like
> EINPROGRESS, ENOTSUP, etc?
>  
>      Error *err = NULL;
>      do_open_tray(..., &err);
>      if (error_num(err) == EINPROGRESS) {
>         ...
>      } else{
>         ...
>      }
> 
> Or should we simply use errno in this case?
> 
> Fam
> 

I can't comment on the historical path that QEMU has taken, but I agree
(Naively?) with pretty much everything you've just written. Perhaps
global, standardized exceptions is too tall of a task to tackle, but you
are right that errors + error codes (or classes) would be useful
precisely for situations like these.



reply via email to

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