patch-1.3.23 linux/drivers/block/genhd.c

Next file: linux/drivers/block/ide-cd.c
Previous file: linux/drivers/block/README.ide
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.22/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
@@ -3,20 +3,17 @@
  *  linux/kernel/hd.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
+ *
+ *
  *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  *  in the early extended-partition checks and added DM partitions
- */
-
-/*
+ *
  *  Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca)
  *  with information provided by OnTrack.  This now works for linux fdisk
  *  and LILO, as well as loadlin and bootln.  Note that disks other than
  *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
- * 
- *  Added support for "missing/deleted" extended partitions - mlord@bnr.ca
+ *
+ *  More flexible handling of extended partitions - aeb, 950831
  */
 
 #include <linux/config.h>
@@ -82,14 +79,15 @@
 {
 	struct buffer_head *bh;
 	struct partition *p;
-	unsigned long first_sector, this_sector;
+	unsigned long first_sector, this_sector, this_size;
 	int mask = (1 << hd->minor_shift) - 1;
+	int i;
 
 	first_sector = hd->part[MINOR(dev)].start_sect;
 	this_sector = first_sector;
 
 	while (1) {
-		if ((current_minor & mask) >= (4 + hd->max_p))
+		if ((current_minor & mask) >= hd->max_p)
 			return;
 		if (!(bh = bread(dev,0,1024)))
 			return;
@@ -100,29 +98,56 @@
 		bh->b_dirt = 0;
 		bh->b_uptodate = 0;
 		bh->b_req = 0;
+
 		if (*(unsigned short *) (bh->b_data+510) != 0xAA55)
 			goto done;
+
 		p = (struct partition *) (0x1BE + bh->b_data);
+
+		this_size = hd->part[MINOR(dev)].nr_sects;
+
 		/*
-		 * Process the first entry, which should be the real
-		 * data partition.
+		 * Usually, the first entry is the real data partition,
+		 * the 2nd entry is the next extended partition, or empty,
+		 * and the 3rd and 4th entries are unused.
+		 * However, DRDOS sometimes has the extended partition as
+		 * the first entry (when the data partition is empty),
+		 * and OS/2 seems to use all four entries.
 		 */
-		if (p->sys_ind == EXTENDED_PARTITION)
-			goto done;	/* shouldn't happen */
-		if (p->sys_ind && p->nr_sects)
-			add_partition(hd, current_minor, this_sector+p->start_sect, p->nr_sects);
-		current_minor++;
-		p++;
+
+		/* 
+		 * First process the data partition(s)
+		 */
+		for (i=0; i<4; i++, p++) {
+		    if (!p->nr_sects || p->sys_ind == EXTENDED_PARTITION)
+		      continue;
+
+		    if (p->start_sect + p->nr_sects > this_size)
+		      continue;
+
+		    add_partition(hd, current_minor, this_sector+p->start_sect, p->nr_sects);
+		    current_minor++;
+		    if ((current_minor & mask) >= hd->max_p)
+		      goto done;
+		}
 		/*
-		 * Process the second entry, which should be a link
-		 * to the next logical partition.  Create a minor
-		 * for this just long enough to get the next partition
-		 * table.  The minor will be reused for the real
+		 * Next, process the (first) extended partition, if present.
+		 * (So far, there seems to be no reason to make
+		 *  extended_partition()  recursive and allow a tree
+		 *  of extended partitions.)
+		 * It should be a link to the next logical partition.
+		 * Create a minor for this just long enough to get the next
+		 * partition table.  The minor will be reused for the next
 		 * data partition.
 		 */
-		if (p->sys_ind != EXTENDED_PARTITION ||
-		    !(hd->part[current_minor].nr_sects = p->nr_sects))
-			goto done;  /* no more logicals in this partition */
+		p -= 4;
+		for (i=0; i<4; i++, p++)
+		  if(p->nr_sects && p->sys_ind == EXTENDED_PARTITION)
+		    break;
+		if (i == 4)
+		  goto done;	 /* nothing left to do */
+
+		hd->part[current_minor].nr_sects = p->nr_sects;
 		hd->part[current_minor].start_sect = first_sector + p->start_sect;
 		this_sector = first_sector + p->start_sect;
 		dev = ((hd->major) << 8) | current_minor;
@@ -211,6 +236,9 @@
 			printk(" <");
 			extended_partition(hd, (hd->major << 8) | minor);
 			printk(" >");
+			/* prevent someone doing mkfs or mkswap on
+			   an extended partition */
+			hd->part[minor].nr_sects = 0;
 		}
 	}
 	/*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this