Linux-kernel mailing list archive 2000-02,: [PATCH] partition handling

# [PATCH] partition handling

Andries.Brouwer@cwi.nl
Fri, 14 Jan 2000 23:44:38 +0100 (MET)

- Messages sorted by: [ date ][ thread ][ subject ][ author ]
- Next message: Jakub Jelinek: "Re: Big Swap..."
- Previous message: Alexander Viro: "Re: [Patch] Cleanup struct gendisk registration, 2.3.40-pre1"

Last month Piotr Wilkin wrote:

: The problem is, that while kernel 2.0.36 sees all the slices AND
: the logical partitions on both disks, kernel 2.2.13 sees all the slices,
: and all the partitions on the first slice, but it doesn't see partitions
: on the second slice. So, while the partition read on 2.0.36 looks like
: this:
:
: hdb: hdb1 < hdb5 hdb6 hdb7 hdb8 > hdb2 < hdb9 hdb10 >
:
: on 2.2.13 (with compiled FreeBSD disklabel support) it looks like this:
:
: hdb: hdb1 hdb2 < hdb5 hdb6 hdb7 hdb8 >

Tigran Aivazian wrote yesterday or so:

: I am not sure the current algorithm for enumerating 3rd party
: partitions is perfect. It makes it very hard to switch between
: booting kernels with and without support for those partitions.
: E.g. I have 2.2.12 from Red Hat 6.1 that has no support for UnixWare
: and FreeBSD partitions and now use 2.3.40-pre1 with support for those
: two and all my normal (i.e. Linux ext2) partitions get shifted around.
: That;s not good.

Such complaints are familiar, and I have sent the patch below to people
complaining to me. Now that I see Tigran's post, let me submit this
for 2.3.40 or so. I just checked that it compiles on 2.3.39.
It yields

Partition check:
hda: hda1 < hda5 hda6 > hda4
hda4: <unixware: hda7 hda8 hda9 hda10 hda11 hda12 hda13 >
hdb: hdb1 hdb2 hdb3 < hdb5 hdb6 hdb7 >
hdc: [PTBL] [4441/255/63] hdc1 hdc2 hdc3 hdc4 < hdc5 >
hdc3: <bsd: hdc6 hdc7 hdc8 hdc9 >

that is, DOS-type partitions are first examined and numbered as
DOS-type partitions, including extended and logical partitions,
and afterwards each is examined for known internal structure.
This way the numbering is a bit more stable, and as a side result
Piotr Wilkin's problem is solved.

Andries

diff -u --recursive --new-file ../linux-2.3.39/linux/fs/partitions/msdos.c ./linux/fs/partitions/msdos.c
--- ../linux-2.3.39/linux/fs/partitions/msdos.c Mon Oct 11 20:49:09 1999
+++ ./linux/fs/partitions/msdos.c Fri Jan 14 22:24:45 2000
@@ -163,25 +163,37 @@
bforget(bh);
}
+static inline struct buffer_head *
+get_partition_table_block(struct gendisk *hd, int minor, int blocknr) {
+ kdev_t dev = MKDEV(hd->major, minor);
+ return bread(dev, blocknr, get_ptable_blocksize(dev));
+}
+
#ifdef CONFIG_SOLARIS_X86_PARTITION
+
+/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
+ indicates linux swap. Be careful before believing this is Solaris. */
+
static void
-solaris_x86_partition(struct gendisk *hd, kdev_t dev, long offset) {
+solaris_x86_partition(struct gendisk *hd, int minor) {
+ long offset = hd->part[minor].start_sect;
struct buffer_head *bh;
struct solaris_x86_vtoc *v;
struct solaris_x86_slice *s;
int i;
+ char buf[40];
- if(!(bh = bread(dev, 0, get_ptable_blocksize(dev))))
+ if(!(bh = get_partition_table_block(hd, minor, 0)))
return;
v = (struct solaris_x86_vtoc *)(bh->b_data + 512);
if(v->v_sanity != SOLARIS_X86_VTOC_SANE) {
brelse(bh);
return;
}
- printk(" <solaris:");
+ printk(" %s: <solaris:", disk_name(hd, minor, buf));
if(v->v_version != 1) {
- printk(" cannot handle version %ld vtoc>", v->v_version);
+ printk(" cannot handle version %ld vtoc>\n", v->v_version);
brelse(bh);
return;
}
@@ -199,21 +211,21 @@
current_minor++;
}
brelse(bh);
- printk(" >");
+ printk(" >\n");
}
#endif
#ifdef CONFIG_BSD_DISKLABEL
-static void check_and_add_bsd_partition(struct gendisk *hd,
- struct bsd_partition *bsd_p, kdev_t dev)
-{
+static void
+check_and_add_bsd_partition(struct gendisk *hd,
+ struct bsd_partition *bsd_p, int minor) {
struct hd_struct *lin_p;
/* check relative position of partitions. */
- for (lin_p = hd->part + 1 + MINOR(dev);
- lin_p - hd->part - MINOR(dev) < current_minor; lin_p++) {
+ for (lin_p = hd->part + 1 + minor;
+ lin_p - hd->part - minor < 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)
+ 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 &&
@@ -244,26 +256,32 @@
add_gd_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,
- int max_partitions)
-{
+static void bsd_disklabel_partition(struct gendisk *hd, int minor, int type) {
struct buffer_head *bh;
struct bsd_disklabel *l;
struct bsd_partition *p;
+ int max_partitions;
int mask = (1 << hd->minor_shift) - 1;
+ char buf[40];
- if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
+ if (!(bh = get_partition_table_block(hd, minor, 0)))
return;
l = (struct bsd_disklabel *) (bh->b_data+512);
if (l->d_magic != BSD_DISKMAGIC) {
brelse(bh);
return;
}
+ printk(" %s:", disk_name(hd, minor, buf));
+ printk((type == OPENBSD_PARTITION) ? " <openbsd:" :
+ (type == NETBSD_PARTITION) ? " <netbsd:" : " <bsd:");
+ max_partitions = ((type == OPENBSD_PARTITION) ? OPENBSD_MAXPARTITIONS
+ : 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++) {
@@ -271,12 +289,13 @@
break;
if (p->p_fstype != BSD_FS_UNUSED)
- check_and_add_bsd_partition(hd, p, dev);
+ check_and_add_bsd_partition(hd, p, minor);
}
/* Use bforget(), as we have changed the disk setup */
bforget(bh);
+ printk(" >\n");
}
#endif
@@ -285,14 +304,14 @@
* Create devices for Unixware partitions listed in a disklabel, under a
* dos-like partition. See extended_partition() for more information.
*/
-static void unixware_partition(struct gendisk *hd, kdev_t dev)
-{
+static void unixware_partition(struct gendisk *hd, int minor) {
struct buffer_head *bh;
struct unixware_disklabel *l;
struct unixware_slice *p;
int mask = (1 << hd->minor_shift) - 1;
+ char buf[40];
- if (!(bh = bread(dev, 14, get_ptable_blocksize(dev))))
+ if (!(bh = get_partition_table_block(hd, minor, 14)))
return;
l = (struct unixware_disklabel *) (bh->b_data+512);
if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
@@ -300,7 +319,7 @@
brelse(bh);
return;
}
- printk(" <unixware:");
+ printk(" %s: <unixware:", disk_name(hd, minor, buf));
p = &l->vtoc.v_slice[1];
/* I omit the 0th slice as it is the same as whole disk. */
while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
@@ -308,30 +327,26 @@
break;
if (p->s_label != UNIXWARE_FS_UNUSED) {
- add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
+ add_gd_partition(hd, current_minor, START_SECT(p),
+ NR_SECTS(p));
current_minor++;
}
p++;
}
/* Use bforget, as we have changed the disk setup */
bforget(bh);
- printk(" >");
+ printk(" >\n");
}
#endif
-int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor)
-{
+int msdos_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor) {
int i, minor = current_minor = first_part_minor;
struct buffer_head *bh;
struct partition *p;
unsigned char *data;
int mask = (1 << hd->minor_shift) - 1;
int sector_size = get_hardsect_size(dev) / 512;
-#ifdef CONFIG_BSD_DISKLABEL
- /* no bsd disklabel as a default */
- kdev_t bsd_kdev = 0;
- int bsd_maxpart = BSD_MAXPARTITIONS;
-#endif
#ifdef CONFIG_BLK_DEV_IDE
int tested_for_xlate = 0;
@@ -345,7 +360,7 @@
#ifdef CONFIG_BLK_DEV_IDE
check_table:
#endif
- /* Use bforget(), because we have potentially changed the disk geometry */
+ /* Use bforget(), because we may have changed the disk geometry */
if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
bforget(bh);
return 0;
@@ -410,11 +425,16 @@
}
#endif /* CONFIG_BLK_DEV_IDE */
+ /* Look for partitions in two passes:
+ First find the primary partitions, and the DOS-type extended partitions.
+ On the second pass look inside *BSD and Unixware and Solaris partitions. */
+
current_minor += 4; /* first "extra" minor (for extended partitions) */
for (i=1 ; i<=4 ; minor++,i++,p++) {
if (!NR_SECTS(p))
continue;
- add_gd_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size);
+ add_gd_partition(hd, minor, first_sector+START_SECT(p)*sector_size,
+ NR_SECTS(p)*sector_size);
if (is_extended_partition(p)) {
printk(" <");
/*
@@ -432,44 +452,8 @@
if (hd->part[minor].nr_sects > 2)
hd->part[minor].nr_sects = 2;
}
-#ifdef CONFIG_BSD_DISKLABEL
- /* tag first disklabel for late recognition */
- if (SYS_IND(p) == BSD_PARTITION || SYS_IND(p) == NETBSD_PARTITION) {
- printk("!");
- if (!bsd_kdev)
- bsd_kdev = MKDEV(hd->major, minor);
- } else if (SYS_IND(p) == OPENBSD_PARTITION) {
- printk("!");
- if (!bsd_kdev) {
- bsd_kdev = MKDEV(hd->major, minor);
- bsd_maxpart = OPENBSD_MAXPARTITIONS;
- }
- }
-#endif
-#ifdef CONFIG_UNIXWARE_DISKLABEL
- if (SYS_IND(p) == UNIXWARE_PARTITION)
- unixware_partition(hd, MKDEV(hd->major, minor));
-#endif
-#ifdef CONFIG_SOLARIS_X86_PARTITION
-
- /* james@bpgc.com: Solaris has a nasty indicator: 0x82
- * which also means linux swap. For that reason, all
- * of the prints are done inside the
- * solaris_x86_partition routine */
-
- if(SYS_IND(p) == SOLARIS_X86_PARTITION) {
- solaris_x86_partition(hd, MKDEV(hd->major, minor),
- first_sector+START_SECT(p));
- }
-#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
*/
@@ -485,6 +469,29 @@
}
}
printk("\n");
+
+ /* second pass - output for each on a separate line */
+ minor -= 4;
+ p = (struct partition *) (0x1be + data);
+ for (i=1 ; i<=4 ; minor++,i++,p++) {
+ if (!NR_SECTS(p))
+ continue;
+#ifdef CONFIG_BSD_DISKLABEL
+ if (SYS_IND(p) == BSD_PARTITION ||
+ SYS_IND(p) == NETBSD_PARTITION ||
+ SYS_IND(p) == OPENBSD_PARTITION)
+ bsd_disklabel_partition(hd, minor, SYS_IND(p));
+#endif
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+ if (SYS_IND(p) == UNIXWARE_PARTITION)
+ unixware_partition(hd, minor);
+#endif
+#ifdef CONFIG_SOLARIS_X86_PARTITION
+ if(SYS_IND(p) == SOLARIS_X86_PARTITION)
+ solaris_x86_partition(hd, minor);
+#endif
+ }
+
bforget(bh);
return 1;
}
diff -u --recursive --new-file ../linux-2.3.39/linux/fs/super.c ./linux/fs/super.c
--- ../linux-2.3.39/linux/fs/super.c Thu Jan 13 05:34:56 2000
+++ ./linux/fs/super.c Thu Jan 13 05:38:37 2000
@@ -932,7 +932,6 @@
/*
* Alters the mount flags of a mounted file system. Only the mount point
* is used as a reference - file system type and the device are ignored.
- * FS-specific mount options can't be altered by remounting.
*/
static int do_remount_sb(struct super_block *sb, int flags, char *data)

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

- Next message: Jakub Jelinek: "Re: Big Swap..."
- Previous message: Alexander Viro: "Re: [Patch] Cleanup struct gendisk registration, 2.3.40-pre1"