Subject: port-i386/15296: kernel ignores partition number when finding disklabel
To: None <gnats-bugs@gnats.netbsd.org>
From: None <david@l8s.co.uk>
List: netbsd-bugs
Date: 01/19/2002 06:19:39
>Number:         15296
>Category:       port-i386
>Synopsis:       kernel ignores partition number when finding disklabel
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    port-i386-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Jan 19 06:20:00 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     David Laight
>Release:        current
>Organization:
>Environment:
NetBSD snowdrop 1.5ZA NetBSD 1.5ZA (GENERIC) #1: Wed Jan 16 17:59:39 GMT 2002
     dsl@snowdrop:/usr/bsd-current/src/sys/arch/i386/compile/GENERIC i386

>Description:
When test a new version it useful to be able to boot 'generic' kernels
off different partitions on the same disk.

Unfortunately the information required is not passed through the many layers
of the boot process.

port-i386/14748's fix changes the mbr_bootsel code
port-i386/15295 fixes the pbr code (/boot etc)

This change fixes the kernel

Note that it isn't possible to write a disklabel (using disklabel) without
the kernel using the specified values.  This might be considerede a bug.

>How-To-Repeat:
Use fdisk to set 2 netBSD partitions and let the mbr_bootsel code pick
either of them.  Boot from the 2nd netbsd partition.

Although the kernel will be loaded from the specified partition,
all the rest of he system will come from the (possibly incompatible)
first partition.

>Fix:
Make the kernel prefer the disklabel from the boot partition.

(I don't quite like the way this fix uses a couple of globals.)
The effect if to prefer the boot sector number from all disks
until the boot disk has been found.  After that only accesses
to the disklabel of the boot disk are affected.

Writes to a disklabel 'prefer' the partition referenced by slice 2
of the disklabel.

Since at least one piece of code required that slice 2 be the disklabel,
I've added code to ensure that is thecase when reading a label.

Fixes are to autoconf.c and disksubr.c in sys/arch/i386/i386

cvs diff autoconf.c
Index: autoconf.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/i386/autoconf.c,v
retrieving revision 1.60
diff -u -r1.60 autoconf.c
--- autoconf.c  2002/01/07 21:47:00     1.60
+++ autoconf.c  2002/01/19 13:55:05
@@ -93,6 +93,8 @@
 
 struct device *booted_device;
 int booted_partition;
+int boot_labelsector;          /* sideways to readdisklavel in disksubr.c */
+dev_t boot_device;             /* ... to find correct disklabel */
 
 /*
  * Determine i/o configuration for a machine.
@@ -288,6 +290,7 @@
         */
        if (bid->labelsector == -1)
                return(0);
+       boot_labelsector = bid->labelsector;
 
        /*
         * lookup major number for disk block device
@@ -333,8 +336,11 @@
        /* compare with our data */
        if (label.d_type == bid->label.type &&
            label.d_checksum == bid->label.checksum &&
-           !strncmp(label.d_packname, bid->label.packname, 16))
+           !strncmp(label.d_packname, bid->label.packname, 16)) {
+               if (!found)
+                   boot_device =  MAKEDISKDEV(i->d_maj, dv->dv_unit, RAW_PART);
                found = 1;
+           }
 
 closeout:
        VOP_CLOSE(tmpvn, FREAD, NOCRED, 0);

 cvs diff disksubr.c
Index: disksubr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/i386/disksubr.c,v
retrieving revision 1.44
diff -u -r1.44 disksubr.c
--- disksubr.c  2001/11/15 07:03:29     1.44
+++ disksubr.c  2002/01/19 13:51:46
@@ -55,8 +55,11 @@
 #define NO_MBR_SIGNATURE ((struct mbr_partition *) -1)
 
 static struct mbr_partition *
-mbr_findslice __P((struct mbr_partition* dp, struct buf *bp));
+mbr_findslice __P((struct mbr_partition* dp, struct buf *bp, int));
 
+int boot_labelsector;          /* extra hints about root disk ... */
+dev_t boot_device = ~0;                /* ... from autoconf.c */
+
 /* 
  * Scan MBR for  NetBSD partittion.  Return NO_MBR_SIGNATURE if no MBR found
  * Otherwise, copy valid MBR partition-table into dp, and if a NetBSD
@@ -64,9 +67,10 @@
  */
 static
 struct mbr_partition *
-mbr_findslice(dp, bp)
+mbr_findslice(dp, bp, label_slice)
        struct mbr_partition *dp;
        struct buf *bp;
+       int label_slice;
 {
        struct mbr_partition *ourdp = NULL;
        u_int16_t *mbrmagicp;
@@ -81,20 +85,25 @@
        memcpy(dp, bp->b_data + MBR_PARTOFF, NMBRPART * sizeof(*dp));
 
        /* look for NetBSD partition */
-       for (i = 0; i < NMBRPART; i++) {
-               if (dp[i].mbrp_typ == MBR_PTYPE_NETBSD) {
-                       ourdp = &dp[i];
-                       break;
+       for (i = 0; i < NMBRPART; i++, dp++) {
+               if (dp->mbrp_typ == MBR_PTYPE_NETBSD) {
+                       if (dp->mbrp_start == label_slice) {
+                               ourdp = dp;
+                               break;
+                       }
+                       if (!ourdp)
+                               ourdp = dp;
                }
        }
 
 #ifdef COMPAT_386BSD_MBRPART
        /* didn't find it -- look for 386BSD partition */
        if (!ourdp) {
-               for (i = 0; i < NMBRPART; i++) {
-                       if (dp[i].mbrp_typ == MBR_PTYPE_386BSD) {
+               dp -= NMBRPART;
+               for (i = 0; i < NMBRPART; i++, dp++) {
+                       if (dp->mbrp_typ == MBR_PTYPE_386BSD) {
                                printf("WARNING: old BSD partition ID!\n");
-                               ourdp = &dp[i];
+                               ourdp = dp;
                                /*
                                 * If more than one matches, take last,
                                 * as NetBSD install tool does.
@@ -107,7 +116,7 @@
        }
 #endif /* COMPAT_386BSD_MBRPART */
 
-               return (ourdp);
+       return (ourdp);
 }
 
 
@@ -189,7 +198,9 @@
        } else {
                struct mbr_partition *ourdp = NULL;
 
-               ourdp = mbr_findslice(dp, bp);
+               ourdp = mbr_findslice(dp, bp,
+                       boot_device == ~0 || dev == boot_device
+                                   ? boot_labelsector - LABELSECTOR : 0);
                if (ourdp ==  NO_MBR_SIGNATURE)
                        goto nombrpart;
 
@@ -272,6 +283,13 @@
                }
        }
 
+       if (lp->d_partitions[2].p_offset != dospartoff) {
+               printf( "slice 2 (%d) doesn't reference label (%d) - fixing\n",
+                       lp->d_partitions[2].p_offset, dospartoff );
+               lp->d_partitions[2].p_offset = dospartoff;
+               lp->d_partitions[2].p_size = LABELSECTOR + 1;
+       }
+
        if (msg)
                goto done;
 
@@ -410,7 +428,7 @@
        if ((error = biowait(bp)) == 0) {
                struct mbr_partition *ourdp = NULL;
 
-               ourdp = mbr_findslice(dp, bp);
+               ourdp = mbr_findslice(dp, bp, lp->d_partitions[2].p_offset);
                if (ourdp ==  NO_MBR_SIGNATURE)
                        goto nombrpart;
 

>Release-Note:
>Audit-Trail:
>Unformatted: