Re: memory waste in fs/devices.c/kdevname()

Riley Williams (rhw@bigfoot.com)
Fri, 18 Dec 1998 22:02:48 +0000 (GMT)


Hi Tigran.

> The current (2.1.131) code is:

> char * kdevname(kdev_t dev)
> {
> static char buffer[32];
> sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
> return buffer;
> }

> But the maximum length of "%02x:%02x" is 6 bytes (including '\0').

Why? %02x only guarantees a MINIMUM of two characters for that field,
so if either MAJOR(dev) or MINOR(dev) are greater than 255, the
relevant field will occupy more than two characters...

> We can throw in a couple of bytes "for good measure" and have
> static char buffer[8] but why on earth do we declare it as [32]?

The following patch should ensure that the minimum number of wasted
bytes are used, as well as automatically dealing with any changes to
the definition of kdev_t that may occur...

===8<=== CUT ===>8===
--- linux/fs/devices.c.orig Mon Aug 24 20:33:11 1998
+++ linux/fs/devices.c Fri Dec 18 21:23:49 1998
@@ -344,7 +344,7 @@
*/
char * kdevname(kdev_t dev)
{
- static char buffer[32];
+ static char buffer[2*sizeof(kdev_t)+4];
sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
return buffer;
}
===8<=== CUT ===>8===

My analysis goes like this: kdev_t is a bitfield that contains both
the major and minor device numbers within it, each occupying an
integral number of bits. There are therefore three separate cases to
be dealt with, depending on precicely where the bits split between the
two fields, as follows:

1. The bitfield and each field within it all occupy a multiple of
four bits, so converts to an exact number of hexadecimal digits.
In this case, the number of characters required to display the
digits in the resulting value is the same as that required to
display the digits in the bitfield itself when printed in hex as
an integral value, ie, 2*sizeof(kdev_t). If we add on the bytes
required for the separator and terminator, we determine that
the requisite number of bytes required is:

2 * sizeof(kdev_t) + 2

2. The bitfield occupies a multiple of four bits, but each of the
fields in it occupies a number of bits that is not a multiple
of four, so does not convert to an exact number of hex digits.
To analyse this case, we try a few possible combinations, and,
to simplify the analysis, I will restrict the bitfield itself
to be 16 bits long, but vary the widths of the other fields:

MAJOR Bytes MINOR Bytes Total
~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~
3 1 13 4 5
5 2 11 3 5
7 2 9 3 5
9 3 7 2 5

As can be seen, the total digits required to display the values
that can result from this case is in each case the same, being
one greater than the number of hex digits required to display
the value of the bitfield as a whole. When the separator and
terminator are included, the resulting formulae becomes:

2 * sizeof(kdev_t) + 3

3. The bitfield occupies a size that is not a multiple of four
bits. In this case, even if one of the subfields has a size
that is a multiple of four bits, the other will have a size
that is not a multiple thereof. Analysis indicates that this
case may result in the use of one extra byte over that of
the earlier cases...

Allowing that for alignment reasons, we would prefer to use a size
which is at least an even number of bytes, so we are quite happy to
assume that case 3 does indeed require the extra byte and use the
formulae stated above...

Comments, anybody?

> And, btw, kdevname() does not seem to be declared anywhere although
> many things use it. Why not stick it in <linux/fs.h> ?

Is it used other than in that one file? If not, there's no need to
declare it in a header file...

Best wishes from Riley.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/