disklabel recognition

Marc Espie (espie@quatramaran.ens.fr)
Thu, 24 Sep 1998 17:45:38 +0200


I'm currently trying to improve bsd disklabel recognition.

There are several problems with the current approach.
First, it does not handle OpenBSD disklabels (partition type A6, max
16 partitions). Then it tends to use up partition entries whenever
some partitions show up both in the disklabel and in the dos partition
table. Finally, when the disklabel changes, all following partitions
are renumbered.

All this is reasonably easy to handle: when I notice a bsd partition,
I just mark it, proceed with extended partitions, then come back and
analyze it. That way, bsd partitions appear after normal partitions,
and I can trim the disklabel for normal dos partitions that I've already
seen.

I'm just wondering if this scheme is building a valid partition table.
You see, bsd partitions do show up after the normal list of partitions,
thus the list of partitions is no longer ordered. Is this likely
to cause trouble ?

Patch is small enough:

diff -ur linux.orig/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux.orig/drivers/block/genhd.c Mon Aug 4 20:45:35 1997
+++ linux/drivers/block/genhd.c Thu Sep 24 18:55:31 1998
@@ -205,11 +206,46 @@
}

#ifdef CONFIG_BSD_DISKLABEL
+static void check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p)
+{
+ struct hd_struct *lin_p;
+ /* check relative position of partitions. */
+ for (lin_p = hd->part + 1; lin_p - hd->part < current_minor; lin_p++) {
+ /* no relationship -> try again */
+ if (lin_p->start_sect + lin_p->nr_sects <= bsd_p->p_offset
+ || lin_p->start_sect >= bsd_p->p_offset + bsd_p->p_size)
+ continue;
+ /* equal -> no need to add */
+ if (lin_p->start_sect == bsd_p->p_offset &&
+ lin_p->nr_sects == bsd_p->p_size)
+ return;
+ /* bsd living within dos partition */
+ if (lin_p->start_sect <= bsd_p->p_offset && lin_p->start_sect
+ + lin_p->nr_sects >= bsd_p->p_offset + bsd_p->p_size) {
+#ifdef DEBUG_BSD_DISKLABEL
+ printk("w: %d %ld+%ld,%d+%d",
+ lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,
+ bsd_p->p_offset, bsd_p->p_size);
+#endif
+ break;
+ }
+ /* ouch: bsd and linux overlap. Don't even try for that partition */
+#ifdef DEBUG_BSD_DISKLABEL
+ printk("???: %d %ld+%ld,%d+%d",
+ lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,
+ bsd_p->p_offset, bsd_p->p_size);
+#endif
+ printk("???");
+ return;
+ } /* if the bsd partition is not described by DOS, we end up there */
+ add_partition(hd, current_minor, bsd_p->p_offset, bsd_p->p_size);
+ current_minor++;
+}
/*
* Create devices for BSD partitions listed in a disklabel, under a
* dos-like partition. See extended_partition() for more information.
*/
-static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev)
+static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev, int max_partitions)
{
struct buffer_head *bh;
struct bsd_disklabel *l;
@@ -225,19 +261,15 @@
return;
}

- p = &l->d_partitions[0];
- while (p - &l->d_partitions[0] <= BSD_MAXPARTITIONS) {
+ if (l->d_npartitions < max_partitions)
+ max_partitions = l->d_npartitions;
+ for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
if ((current_minor & mask) >= (4 + hd->max_p))
break;
-
- if (p->p_fstype != BSD_FS_UNUSED) {
- add_partition(hd, current_minor, p->p_offset, p->p_size);
- current_minor++;
- }
- p++;
+ if (p->p_fstype != BSD_FS_UNUSED)
+ check_and_add_bsd_partition(hd, p);
}
brelse(bh);
-
}
#endif

@@ -248,6 +280,11 @@
struct partition *p;
unsigned char *data;
int mask = (1 << hd->minor_shift) - 1;
+#ifdef CONFIG_BSD_DISKLABEL
+ /* no bsd disklabel as a default */
+ kdev_t bsd_kdev = 0;
+ int bsd_maxpart;
+#endif
#ifdef CONFIG_BLK_DEV_IDE
int tested_for_xlate = 0;

@@ -365,13 +402,29 @@
hd->part[minor].nr_sects = 2;
}
#ifdef CONFIG_BSD_DISKLABEL
+ /* tag first disklabel for late recognition */
if (SYS_IND(p) == BSD_PARTITION) {
- printk(" <");
- bsd_disklabel_partition(hd, MKDEV(hd->major, minor));
- printk(" >");
+ printk("!");
+ if (!bsd_kdev) {
+ bsd_kdev = MKDEV(hd->major, minor);
+ bsd_maxpart = BSD_MAXPARTITIONS;
+ }
+ } else if (SYS_IND(p) == OPENBSD_PARTITION) {
+ printk("!");
+ if (!bsd_kdev) {
+ bsd_kdev = MKDEV(hd->major, minor);
+ bsd_maxpart = OPENBSD_MAXPARTITIONS;
+ }
}
#endif
}
+#ifdef CONFIG_BSD_DISKLABEL
+ if (bsd_kdev) {
+ printk(" <");
+ bsd_disklabel_partition(hd, bsd_kdev, bsd_maxpart);
+ printk(" >");
+ }
+#endif
/*
* Check for old-style Disk Manager partition table
*/
diff -ur linux.orig/include/linux/genhd.h linux/include/linux/genhd.h
--- linux.orig/include/linux/genhd.h Wed Mar 18 20:25:30 1998
+++ linux/include/linux/genhd.h Thu Sep 24 18:55:43 1998
@@ -69,12 +70,19 @@
#ifdef CONFIG_BSD_DISKLABEL
/*
* BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
+ *
+ * updated by Marc Espie <Marc.Espie@openbsd.org>
*/

+/* check against BSD src/sys/sys/disklabel.h for consistency */
+
#define BSD_PARTITION 0xa5 /* Partition ID */
+#define OPENBSD_PARTITION 0xa6

#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
#define BSD_MAXPARTITIONS 8
+#define OPENBSD_MAXPARTITIONS 16
+
#define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */
struct bsd_disklabel {
__u32 d_magic; /* the magic number */

-
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/