qemu-devel
[Top][All Lists]
Advanced

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

Re: [PATCH 2/4] smbus: Fix spd_data_generate() error API violation


From: Markus Armbruster
Subject: Re: [PATCH 2/4] smbus: Fix spd_data_generate() error API violation
Date: Fri, 24 Apr 2020 11:45:18 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux)

BALATON Zoltan <address@hidden> writes:

> On Tue, 21 Apr 2020, Markus Armbruster wrote:
>> BALATON Zoltan <address@hidden> writes:
>>> On Mon, 20 Apr 2020, Markus Armbruster wrote:
>>>> The Error ** argument must be NULL, &error_abort, &error_fatal, or a
>>>> pointer to a variable containing NULL.  Passing an argument of the
>>>> latter kind twice without clearing it in between is wrong: if the
>>>> first call sets an error, it no longer points to NULL for the second
>>>> call.
>>>>
>>>> spd_data_generate() can pass @errp to error_setg() more than once when
>>>> it adjusts both memory size and type.  Harmless, because no caller
>>>> passes anything that needs adjusting.  Until the previous commit,
>>>> sam460ex passed types that needed adjusting, but not sizes.
>>>>
>>>> spd_data_generate()'s contract is rather awkward:
>>>>
>>>>    If everything's fine, return non-null and don't set an error.
>>>>
>>>>    Else, if memory size or type need adjusting, return non-null and
>>>>    set an error describing the adjustment.
>>>>
>>>>    Else, return null and set an error reporting why no data can be
>>>>    generated.
>>>>
>>>> Its callers treat the error as a warning even when null is returned.
>>>> They don't create the "smbus-eeprom" device then.  Suspicious.
>>>
>>> The idea here again is to make it work if there's a way it could work
>>> rather than throw back an error to user and bail. This is for user
>>> convenience in the likely case the user knows nothing about the board
>>> or SPD data restrictions.
>>
>> We're in perfect agreement that the user of QEMU should not need to know
>> anything about memory type and number of banks.  QEMU should pick a
>> sensible configuration for any memory size it supports.
>
> I though it could be useful to warn the users when QEMU had to fix up
> some values to notify them that what they get may not be what they
> expect and can then know why.

*If* QEMU "fixed up" the user's configuration, then QEMU should indeed
warn the user.

But it doesn't fix up anything here.  This broken code is unused.

>                               If the message really annoys you you can
> remove it but I think it can be useful. I just think your real problem
> with it is that Error can't support it so it's easier to remove the
> warning than fixing Error or use warn_report instead.

It's indeed easier to remove broken unused code than to try fixing it.
YAGNI.

>>>                           You seem to disagree with this
>>
>> Here's what I actually disagree with:
>>
>> 1. QEMU warning the user about its choice of memory type, but only
>> sometimes.  Why warn?  There is nothing wrong, and there is nothing the
>> user can do to avoid the condition that triggers the warning.
>
> The memory size that triggers the warning is specified by the user so
> the user can do someting about it.

There is no way to trigger the warning.  If we dropped PATCH 1 instead
of fixing it as I did in v2, then the only way to trigger the warning is
-M sam460ex -m 64 or -m 32, and the only way to avoid it is to don't do
that.

Why would a user care whether he gets DDR or DDR2 memory?

>> 2. QEMU changing the user's memory size.  Yes, I understand that's an
>> attempt to be helpful, but I prefer my tools not to second-guess my
>> intent.
>
> I agree with that and also hate Windows's habit of trying to be more
> intelligent than the user and prefer the Unix way however the average
> users of QEMU (from my perpective, who wants to run Amiga like OSes
> typically on Windows and for the most part not knowing what they are
> doing) are already intimidated by the messy QEMU command line
> interface and will specify random values and complain or go away if it
> does not work so making their life a little easier is not
> useless. These users (or any CLI users) are apparently not relevant
> from your point of view but they do exist and I think should be
> supported better.

This theoretical.  Remember, we're talking about unused code.  Proof:

    $ ppc-softmmu/qemu-system-ppc -M sam460ex -m 4096
    qemu-system-ppc: Max 1 banks of 2048 ,1024 ,512 ,256 ,128 ,64 ,32 MB 
DIMM/bank supported
    qemu-system-ppc: Possible valid RAM size: 2048

I figure commit a0258e4afa "ppc/{ppc440_bamboo, sam460ex}: drop RAM size
fixup" removed the only uses.  If you disagree with it, take it up with
Igor, please.

>>>                                                          and want to
>>> remove all such logic from everywhere. Despite the title of this patch
>>> it's not just fixing error API usage but removing those fix ups.
>>
>> I'm removing unused code that is also broken.  If you want to keep it,
>> please fix it, and provide a user and/or a unit test.  Without that, it
>> is a trap for future callers.
>
> What was broken in this patch? Isn't freeing the previous warning when

My commit message explains:

     The Error ** argument must be NULL, &error_abort, &error_fatal, or a
     pointer to a variable containing NULL.  Passing an argument of the
     latter kind twice without clearing it in between is wrong: if the
     first call sets an error, it no longer points to NULL for the second
     call.

     spd_data_generate() can pass @errp to error_setg() more than once when
     it adjusts both memory size and type.  Harmless, because no caller
     passes anything that needs adjusting.  Until the previous commit,
     sam460ex passed types that needed adjusting, but not sizes.

Now have a look at the code I delete:

    if (size < 4) {
        error_setg(errp, "SDRAM size is too small");
        return NULL;
    }
    sz_log2 = 31 - clz32(size);
    size = 1U << sz_log2;
    if (ram_size > size * MiB) {
--->    error_setg(errp, "SDRAM size 0x"RAM_ADDR_FMT" is not a power of 2, "
                   "truncating to %u MB", ram_size, size);
    }
    if (sz_log2 < min_log2) {
--->    error_setg(errp,
                   "Memory size is too small for SDRAM type, adjusting type");
        if (size >= 32) {
            type = DDR;
            min_log2 = 5;
            max_log2 = 12;
        } else {
            type = SDR;
            min_log2 = 2;
            max_log2 = 9;
        }
    }
    [...]
    if (size > (1ULL << sz_log2) * nbanks) {
--->    error_setg(errp, "Memory size is too big for SDRAM, truncating");
    }

If more than one of the conditions guarding these error_setg() is true,
and @errp is neither null, &error_abort, nor &error_fatal, then it'll
point to an Error * that is not null for the non-first error_setg()
call.  This will trip the assertion in error_setv().

> adding a new one or combining them as you say below (although I don't
> really get what you mean) would fix it without removing fix ups? It's
> only unused now because in previous patches you've removed all usages:
> first broke memory fixup because of some internal QEMU API did not
> support fixing up memory size so instead of fixing that API removed
> what did not fit, then now removing type fix ups because it's not
> fitting Error API.
>
> Originally it did work well and produced usable values for whatever
> number the user specified and it was convenient for users. (Especially
> the sam460ex is a problematic case because of SoC and firmware limits
> that the user should not need to know about.)

I don't doubt it worked in your testing.

It's still wrong.

>>> If Error cannot be used for this could you change error_setg to
>>> warn_report and keep the fix ups untouched? That fixes the problem
>>> with error (although leaves no chance to board code to handle
>>> errors). Maybe fix Error to be usable for what it's intended for
>>> rather than removing cases it can't handle.
>>
>> Error is designed for errors, not warnings.
>>
>> A function either succeeds (no error) or fails (one error).
>>
>> It can be pressed into service for warnings (you did, although in a
>> buggy way).  You still can return at most one Error per Error **
>> parameter.  If you need multiple warnings, use multiple parameters
>> (ugh!).  You could also try to squash multiple warnings into one the
>> hints mechanism.
>>
>> I'd advise against combining warn_report() and Error ** in one function.
>> A function should either take care of talking to the user completely, or
>> leave it to its caller completely.
>
> I've tried to use error so the board code can decide what's an error
> and what's a warning but if this cannot be done with this QEMU
> facility I don't know a better way than using warn_report for
> warnings.

Is there any board that genuinely wants to decide what's an error and
what's a warning?

Here's spd_data_generate() contract again:

        If everything's fine, return non-null and don't set an error.

        Else, if memory size or type need adjusting, return non-null and
        set an error describing the adjustment.

        Else, return null and set an error reporting why no data can be
        generated.

It has a grand total of two users.  Both treat the second case as
warning, and the third as error.

Until you have a user that wants to handle things differently, you're
overcomplicating things.

YAGNI!




reply via email to

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