Subject: Re: 32 bit dev_t
To: Todd Vierling <tv@NetBSD.ORG>
From: Charles M. Hannum <email@example.com>
Date: 01/13/1998 17:25:25
Todd Vierling <tv@NetBSD.ORG> writes:
> On Tue, 13 Jan 1998, Charles M. Hannum wrote:
> : * As an alternative to renumbering, you could instead make the minor
> : number non-contiguous; i.e.:
> : 3322222222221111111111
> : 10987654321098765432109876543210
> : |--minor---||--major---||minor-| new
> : |major-||minor-| old
> : * Given the above scheme, should we decide to renumber everything at
> : some point (hopefully only once!!!), we can simply choose some portion
> : of the major numbers (say, the first 256) and use them for
> : `compatibility'. There's no need to waste half the number space.
> But there's a
> big problem with splitting the numbers this way: kernel overhead.
> Disassembling and reassembling pieces of ints turns a bitand-and-shiftright
> into a (bitand)-bitor-(bitand-and-shiftright). Not that this is too bad,
> but it's more than it is worth, particularly if you need to look at a
> hexadecimal dev_t in kernel data dumps and figure out what it is. Why
> bother, if the dev_t's will be renumbered anyway?
Uh, IF YOU DO WHAT I SAID BELOW, then this occurs exactly once each
time the spec node is creating. I'm sure this is much more overhead
than calling a complicated function several times every time you
reference the device node. (NOT!)
> : * If you're going to change all the existing device numbers, rather
> : than turning major() and minor() into functions, you should do any
> : old->new conversion (if necessary) in checkalias(), before it's put in
> : v_specinfo. This value is *only* used internally to the kernel.
> Well, only internally to the kernel, but not necessarily in just one place.
> And it's not the only place that cares about the value of a dev_t.
You're missing the point, clearly.
All internal uses of dev_t use the value in v_specinfo. All cases
where the data is returned to the user get it directly from the file
system. Ergo, you only ever need to do conversion when filling in
v_specinfo, and it's totally transparent to the user. There's *no*
need to make the major() and minor() macros complex; you already have
a convenient single point to do the conversion, so USE it.
> is, as I see it, if I were to convert the value before it gets put into an
> info structure, then __stat13() would break--it would get the (converted)
> value of a dev_t, which is *not* what we want.
If you believe that, then you clearly didn't read what I wrote before.
To quote myself: `This value is *only* used internally to the kernel.
(You'll note that the device number returned by *stat(2) is taken
directly from the file system through *_getattr().)'
> : (Think about what you're proposing doing to your serial port read()
> : path, for example. A couple of calls to major(), one to minor(), etc.
> : How many more layers of indirection before you make it slow enough
> : that nobody wants to use it any more?)
> Let me quote my /sys/sys/types.h:
> typedef u_int32_t dev_t; /* device number */
> #if defined(_KERNEL) && defined(COMPAT_13)
> extern const dev_t __devcvt32 __P((dev_t)); /* convert major _and_ minor */
> extern const u_int __devcvt32maj __P((dev_t)); /* convert major (faster) */
> #define devcvt32(x) ((dev_t)(x) & 0xfff00000 ? (dev_t)(x) : __devcvt32(x))
> #define major(x) ((u_int)(x) & 0xfff00000 ? \
> ((u_int)(x) >> 20) & 0xfff : __devcvt32maj(x))
> #define minor(x) ((u_int)(devcvt32(x) & 0xfffff))
> #define makedev(x,y) (((((dev_t)(x) & 0xfff) << 20) | ((dev_t)(y) & 0xfffff)))
> #define devcmp(x,y) (devcvt32(x) != devcvt32(y))
> You'll note that I added inline checks for `new' and `old' devices in
> major(), minor(), devcvt32(), and devcmp(). If a device is `new', a
> function call is never made. Better yet, these all drop out if COMPAT_13 is
Uh, `that's nice'. My proposal avoided doing the function calls *in
any case* in critical paths. Virtually 0 overhead for either new or
old device numbers.
> : * We can't have stat(2) or mknod(2) magically change device numbers
> : behind our back. For example, consider using pax(1) to pack or unpack
> : a file system used by another operating system. Total lossage.
> Well, that will automagically happen if the specinfo struct gets changed,
> won't it?
> But, if you're unpacking device nodes for a different system, and you're
> going to use them locally instead of exported, you're going to lose. :>
That was, obviously, *not* the point.