Re2: [PATCH] fix /boot/loader for extended slices
Matthew Dillon
dillon at apollo.backplane.com
Sun Dec 19 12:21:04 PST 2004
Ok, I've gone through it and cleaned up a bunch of stuff. I
changed your pre-increment in the recursion with code to properly
set the starting extended slice to 4 and then post-incrementing
(instead of setting it to 3 and pre-incremented, which is confusing
to say the least).
I also added in a bounds check against the maximum size of the
in-memory array to avoid overflows.
Then, and this is the part I'm not sure about, I noticed that
your extended partition recursion check was not iterating through
the four slice table entries in each extended slice. It seemed
to be checking just the first one. So I changed it to iterate.
And, finally, after looking at the kernel slice table scanner I
noticed that the kernel seems to use a breadth-first traversal
whereas the boot loader appears to have been using a depth-first
traversal. I changed the boot-loader to use a breadth-first
traversal.
My test boxes are not currently setup with extended partitions
so I would appreciate testing.
-Matt
Index: biosdisk.c
===================================================================
RCS file: /cvs/src/sys/boot/i386/libi386/biosdisk.c,v
retrieving revision 1.8
diff -u -r1.8 biosdisk.c
--- biosdisk.c 24 Oct 2004 18:36:05 -0000 1.8
+++ biosdisk.c 19 Dec 2004 20:20:29 -0000
@@ -135,7 +135,7 @@
static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev);
static void bd_closedisk(struct open_disk *od);
static int bd_bestslice(struct open_disk *od);
-static void bd_checkextended(struct open_disk *od, int slicenum);
+static void bd_chainextended(struct open_disk *od, u_int32_t base, u_int32_t offset);
/*
* Translate between BIOS device numbers and our private unit numbers.
@@ -517,17 +517,34 @@
}
/*
- * copy the partition table, then pick up any extended partitions.
+ * copy the partition table, then pick up any extended partitions. The
+ * base partition table always has four entries, even if some of them
+ * represented extended partitions. However, any additional sub-extended
+ * partitions will be silently recursed and not included in the slice
+ * table.
*/
bcopy(buf + DOSPARTOFF, &od->od_slicetab,
sizeof(struct dos_partition) * NDOSPART);
- od->od_nslices = 4; /* extended slices start here */
- for (i = 0; i < NDOSPART; i++)
- bd_checkextended(od, i);
+ od->od_nslices = NDOSPART;
+
+ dptr = &od->od_slicetab[0];
+ for (i = 0; i < NDOSPART; i++, dptr++) {
+ if ((dptr->dp_typ == DOSPTYP_EXT) || (dptr->dp_typ == DOSPTYP_EXTLBA))
+ bd_chainextended(od, dptr->dp_start, 0); /* 1st offset is zero */
+ }
od->od_flags |= BD_PARTTABOK;
dptr = &od->od_slicetab[0];
- /* Is this a request for the whole disk? */
+ /*
+ * Overflow entries are not loaded into memory but we still keep
+ * track of the count. Fix it up now.
+ */
+ if (od->od_nslices > NEXTDOSPART)
+ od->od_nslices = NEXTDOSPART;
+
+ /*
+ * Is this a request for the whole disk?
+ */
if (dev->d_kind.biosdisk.slice == -1) {
sector = 0;
goto unsliced;
@@ -637,47 +654,82 @@
return(error);
}
+
static void
-bd_checkextended(struct open_disk *od, int slicenum)
+bd_chainextended(struct open_disk *od, u_int32_t base, u_int32_t offset)
{
- char buf[BIOSDISK_SECSIZE];
- struct dos_partition *dp;
- u_int base;
- int i, start, end;
+ char buf[BIOSDISK_SECSIZE];
+ struct dos_partition *dp1, *dp2;
+ int i;
- dp = &od->od_slicetab[slicenum];
- start = od->od_nslices;
+ if (bd_read(od, (daddr_t)(base + offset), 1, buf)) {
+ printf("\nerror reading extended partition table");
+ return;
+ }
+
+ /*
+ * dp1 points to the first record in the on-disk XPT,
+ * dp2 points to the next entry in the in-memory parition table.
+ *
+ * NOTE: dp2 may be out of bounds if od_nslices >= NEXTDOSPART.
+ *
+ * NOTE: unlike the extended partitions in our primary dos partition
+ * table, we do not record recursed extended partitions themselves
+ * in our in-memory partition table.
+ *
+ * NOTE: recording within our in-memory table must be breadth first
+ * ot match what the kernel does. Thus, two passes are required.
+ */
+ dp1 = (struct dos_partition *)(&buf[DOSPARTOFF]);
+ dp2 = &od->od_slicetab[od->od_nslices];
- if (dp->dp_size == 0)
- goto done;
- if (dp->dp_typ != DOSPTYP_EXT)
- goto done;
- if (bd_read(od, (daddr_t)dp->dp_start, 1, buf))
- goto done;
- if (((u_char)buf[0x1fe] != 0x55) || ((u_char)buf[0x1ff] != 0xaa)) {
- DEBUG("no magic in extended table");
- goto done;
- }
- base = dp->dp_start;
- dp = (struct dos_partition *)(&buf[DOSPARTOFF]);
- for (i = 0; i < NDOSPART; i++, dp++) {
- if (dp->dp_size == 0)
+ for (i = 0; i < NDOSPART; ++i, ++dp1) {
+ if (dp1->dp_scyl == 0 && dp1->dp_shd == 0 &&
+ dp1->dp_ssect == 0 && dp1->dp_start == 0 &&
+ dp1->dp_size == 0) {
continue;
- if (od->od_nslices == NEXTDOSPART)
- goto done;
- dp->dp_start += base;
- bcopy(dp, &od->od_slicetab[od->od_nslices], sizeof(*dp));
- od->od_nslices++;
+ }
+ if ((dp1->dp_typ == DOSPTYP_EXT) ||
+ (dp1->dp_typ == DOSPTYP_EXTLBA)) {
+ /*
+ * breadth first traversal, must skip in the
+ * first pass
+ */
+ continue;
+ }
+
+ /*
+ * Only load up the in-memory data if we haven't overflowed
+ * our in-memory array.
+ */
+ if (od->od_nslices < NEXTDOSPART) {
+ dp2->dp_typ = dp1->dp_typ;
+ dp2->dp_start = base + offset + dp1->dp_start;
+ dp2->dp_size = dp1->dp_size;
+ }
+ ++od->od_nslices;
+ ++dp2;
}
- end = od->od_nslices;
/*
- * now, recursively check the slices we just added
+ * Pass 2 - handle extended partitions. Note that the extended
+ * slice itself is not stored in the slice array when we recurse,
+ * but any 'original' top-level extended slices are. This is to
+ * match what the kernel does.
*/
- for (i = start; i < end; i++)
- bd_checkextended(od, i);
-done:
- return;
+ dp1 -= NDOSPART;
+ for (i = 0; i < NDOSPART; ++i, ++dp1) {
+ if (dp1->dp_scyl == 0 && dp1->dp_shd == 0 &&
+ dp1->dp_ssect == 0 && dp1->dp_start == 0 &&
+ dp1->dp_size == 0) {
+ continue;
+ }
+ if ((dp1->dp_typ == DOSPTYP_EXT) ||
+ (dp1->dp_typ == DOSPTYP_EXTLBA)) {
+ bd_chainextended(od, base, dp1->dp_start);
+ continue;
+ }
+ }
}
/*
@@ -714,7 +766,6 @@
dp = &od->od_slicetab[0];
for (i = 0; i < od->od_nslices; i++, dp++) {
-
switch (dp->dp_typ) {
case DOSPTYP_386BSD: /* FreeBSD */
pref = dp->dp_flag & 0x80 ? PREF_FBSD_ACT : PREF_FBSD;
More information about the Submit
mailing list