I have a dread sense that I'm going to regret asking questions, but I'm 
going to do it anyway, because hey, what the hell, I can always drink 
bleach.

On Fri, 24 Apr 2020 19:09:53 -0600, Theo de Raadt wrote:
[snip]
> 
> Reality hasn't changed.  A sector is still 512 bytes, and
> disklabel has to fit in it.

I doubt that it will improve anything, but some of us (well, at least 
me) got intrigued by your answers and the history (I thought that 
sixteen was chosen because four bits and it was significant for that 
reason, but that was clearly leaping to the same sorts of conclusions 
from a different direction than disk size, which was embarrassing). So 
I went and had a look at the struct definition.

Some summary for misc-readers who are not Theo or other devs; y'all 
skip over me doing base-level analysis, 'kay? Otherwise you'll be rilly 
annoyed with me for seeming to talk down to you, but this is for the 
other folks who responded on thread without looking at disklabel.h.

/usr/src/sys/disklabel.h, the struct disklabel is the bit in question:

struct disklabel {
        u_int32_t d_magic;              /* the magic number */
        u_int16_t d_type;               /* drive type */
        u_int16_t d_subtype;            /* controller/d_type specific */
        char      d_typename[16];       /* type name, e.g. "eagle" */
        char      d_packname[16];       /* pack identifier */

                        /* disk geometry: */
        u_int32_t d_secsize;            /* # of bytes per sector */
        u_int32_t d_nsectors;           /* # of data sectors per track 
*/
        u_int32_t d_ntracks;            /* # of tracks per cylinder */
        u_int32_t d_ncylinders;         /* # of data cylinders per unit 
*/
        u_int32_t d_secpercyl;          /* # of data sectors per 
cylinder */
        u_int32_t d_secperunit;         /* # of data sectors (low part) 
*/

        u_char  d_uid[8];               /* Unique label identifier. */

        /*
         * Alternate cylinders include maintenance, replacement, 
configuration
         * description areas, etc.
         */
        u_int32_t d_acylinders;         /* # of alt. cylinders per unit 
*/

                        /* hardware characteristics: */
        u_int16_t d_bstarth;            /* start of useable region 
(high part) */
        u_int16_t d_bendh;              /* size of useable region (high 
part) */
        u_int32_t d_bstart;             /* start of useable region */
        u_int32_t d_bend;               /* end of useable region */
        u_int32_t d_flags;              /* generic flags */
#define NDDATA 5
        u_int32_t d_drivedata[NDDATA];  /* drive-type specific 
information */
        u_int16_t d_secperunith;        /* # of data sectors (high 
part) */
        u_int16_t d_version;            /* version # (1=48 bit 
addressing) */
#define NSPARE 4
        u_int32_t d_spare[NSPARE];      /* reserved for future use */
        u_int32_t d_magic2;             /* the magic number (again) */
        u_int16_t d_checksum;           /* xor of data incl. partitions 
*/

                        /* filesystem and partition information: */
        u_int16_t d_npartitions;        /* number of partitions in 
following */
        u_int32_t d_bbsize;             /* size of boot area at sn0, 
bytes */
        u_int32_t d_sbsize;             /* max size of fs superblock, 
bytes */

/* at this point, the struct as a whole occupies 160 bytes, in general 
metadata
   about the disklabel-as-a-whole, not any specific partition. next is 
partitions: */

        struct  partition {             /* the partition table */
                u_int32_t p_size;       /* number of sectors (low part) 
*/
                u_int32_t p_offset;     /* starting sector (low part) */
                u_int16_t p_offseth;    /* starting sector (high part) 
*/
                u_int16_t p_sizeh;      /* number of sectors (high 
part) */
                u_int8_t p_fstype;      /* filesystem type, see below */
                u_int8_t p_fragblock;   /* encoded filesystem 
frag/block */
                u_int16_t p_cpg;        /* UFS: FS cylinders per group 
*/
        } d_partitions[MAXPARTITIONS];  /* actually may be more */
};

struct partition is 16 bytes, times MAXPARTITIONS.

Note that MAXPARTITIONS isn't defined in this header; it's in the 
per-arch disklabel.h (/usr/src/arch/*/include/disklabel.h). On the 
other hand, at the top of the file is this:

/*
 * The absolute maximum number of disk partitions allowed.
 * This is the maximum value of MAXPARTITIONS for which 'struct 
disklabel'
 * is <= DEV_BSIZE bytes long.  If MAXPARTITIONS is greater than this, 
beware.
 */
#define MAXMAXPARTITIONS        22
#if MAXPARTITIONS > MAXMAXPARTITIONS
#warn beware: MAXPARTITIONS bigger than MAXMAXPARTITIONS
#endif

Now, to cut to the chase, /usr/src/arch/*/include/disklabel.h all have 
"#define MAXPARTITIONS 16" (whitespace varies, but the number doesn't). 
So the standard/universal 16 partitions take up 256 bytes in the array 
of struct partition. Therefore:

160 + 256 = 416 (which is, of course, less than 512)

The comment on MAXMAXPARTITIONS says that 22 is the utmost limit; 16*22 
= 352. Add 352 to 160 and ta-da! 512. The limit, as repeated several 
times.

Now for the question! If you're skipping over junior-dev-level 
analysis, here's where I switch to whining piteously.

So, and I recognize that the answer might reasonably be "go read more 
code and figure it out yourself," a question for Theo and others if you 
have a moment: why couldn't an arch expand past sixteen? It seems, both 
from the math calculating struct size (which may be mistaken, in which 
case I apologize) and in the comment for MAXMAXPARTITIONS that more 
*are* possible. Even if part of the reason is to preserve space within 
the sector for future changes (for instance, to allow the size of the 
global part of the struct to increase to 176 or 192 bytes, effectively 
leaving reserved bits), couldn't MAXPARTITIONS increase to 20 on arches 
where us misc-readers are whining about it?

No, I haven't a patch to offer. I'm not certain that increasing 
MAXPARTITIONS without any other changes would break things, but with a 
magic number in the disklabel, I'm guessing that there are expectations 
of the content elsewhere that may require additional changes. But the 
partitions array is final in its containing struct, which looks like 
design for later expansion.

I'm also not asking that it be done, or that anyone do the research 
*for* me, I'm really just wondering if someone knows the answer 
off-hand. What are the obstacles to increasing MAXPARTITIONS to 20 on 
amd64? (chosen because it's the arch I'm using)

Amy!
-- 
Amelia A. Lewis                    amyzing {at} talsever.com
Never imagine yourself not to be otherwise than what it might appear to
others that what you were or might have been was not otherwise than what
you had been would have appeared to them to be otherwise.
                -- The Duchess [Lewis Carroll]

Reply via email to