Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 8 Jan 2016 17:04:55 +1100 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Jim Harris <jim.harris@gmail.com>
Cc:        Ravi Pokala <rpokala@mac.com>, src-committers@freebsd.org,  svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   Re: svn commit: r293328 - head/sys/dev/nvme
Message-ID:  <20160108160312.Y1626@besplex.bde.org>
In-Reply-To: <CAJP=Hc9roQUH2kqogjeXYUvs1wCVaz-9GGz1cd%2BCqnHr6GwACQ@mail.gmail.com>
References:  <201601071618.u07GIXdd054147@repo.freebsd.org> <6496C054-6FED-4B41-8EF8-8067E8B6C866@panasas.com> <CAJP=Hc9roQUH2kqogjeXYUvs1wCVaz-9GGz1cd%2BCqnHr6GwACQ@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 7 Jan 2016, Jim Harris wrote:

> On Thu, Jan 7, 2016 at 9:27 AM, Ravi Pokala <rpokala@mac.com> wrote:
> ...
>>> + * Used for calculating number of CPUs to assign to each core and number
>> of I/O
>>> + *  queues to allocate per controller.
>>> + */
>>> +#define NVME_CEILING(num, div)        ((((num) - 1) / (div)) + 1)
>>> +
>>>
>>> ...
>>
>> I'm surprised that this isn't in <sys/param.h>, along with
>> roundup()/rounddown()/etc. Finding the ceiling like this is probably pretty
>> common, so shouldn't it be added to the common header so everyone can use
>> it?
>
> Good catch.  howmany() does exactly this, just expressed differently.  I'll
> switch over to that.  Thanks!

howmany() doesn't do exactly this.  It has diferent bugs / range of
applicability,  I see about 10.  Subtracting 1 instead of adding more
than 1 gives overflow in different cases.  Even the simple and not
unreasonable case num = 0 gives overflow in NVME_CEILING() if div happens
to be unsigned and not 1: NVME_CEILING(0, 2U) = UINTMAX / 2 + 1 =
0x80000000 with 32-bit ints.

Getting to 10 different bugs requires considering unreasonable cases
with negative div or num, and nonsense cases with div = 0, and
reasonable but unsupported cases with floating point args.  C's broken
division for negative integer values makes the details large.
NVME_CEILING() is closer to supporting negative values than howmany()
-- the magic 1 that it adds is to adjust for division of non-negative
values rounding down.  For division of negative values, the adjustment
should be by -1 or 0, depending on the C bug and on whether you want
to round negative results towards 0 or minus infinity.

Howmany() is undocumented so its bugs are harder to see than in your own
macro.  Another one is that it is an unsafe macro with the name of a safe
function-like API.  This naming convention is more important for undocumented
APIs.  NVME_CEILING() follows it in reverse.  Subtracting 1 instead of
adding (div) - 1 is less robust but avoids multiple evaluation of div.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20160108160312.Y1626>