[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#59385: [PATCH] Fixes for BSD disklabel support (for Alpha)



Package: util-linux
Version: 2.10f-2
Severity: important

Hi,

Right now it is very, very difficult to partition disks in the
installer on Alpha when using BSD disklabels (as you must when booting
from SRM).  This is a problem because SRM is now the recommended way
of booting Linux on nearly all Alphas.

This patch *MUST* go into potato, which is why I've marked it as
important.  Nothing personal, I just want to get your attention :)

This patch addresses a few important usability issues:

 1) Digital Unix has a rather different (probably more correct) idea
    of the actual geometry of disks, and stores this in its
    disklabels.  fdisk was ignoring the values in the disklabel and
    using the Linux kernel's idea of the number of sectors per
    cylinder.  This made it nearly impossible to repartition disks
    that had previously been set up using diskconfig in DEC Unix,
    since the cylinder values shown were incorrect, and also different
    (!) from the values accepted by the 'new partition' command.
    Also, it wasn't very easy to partition by sector, because:

 2) When partitioning by sector rather than by cylinder, only the
    offset and size were shown in sectors.

 3) fdisk started up in DOS partition table mode regardless of whether
    an OSF/1 disklabel existed on the disk.

 4) There was no way to switch from cylinders to sectors from within
    disklabel mode, nor was there any way to return to DOS partition
    mode on an Alpha.

This patch isn't the most elegant way to handle this, but since on
i386, disklabels will always be a bag on the side of the DOS partition
table, we can't make it nice and pretty like the Sun and SGI disklabel
support...

Also, writing the disklabel causes unaligned access errors, and it's
just bad style to declare a static variable ('buffer') with the same
name as a global variable, so I cleaned that stuff up.  Finally, I
added some bits to make it recognize Digital Unix AdvFS partitions as
such.

If someone could please test this on i386 machines to make sure it
doesn't break disklabels there, I'd appreciate that.

There are also some patches from people at Compaq that fix a few other
bugs, which I'll be submitting in a separate report when I get them.

Cheers

diff --exclude=*~ -urN util-linux-2.10f/fdisk/fdisk.c util-linux-2.10f.patched/fdisk/fdisk.c
--- util-linux-2.10f/fdisk/fdisk.c	Fri Jan 21 19:19:37 2000
+++ util-linux-2.10f.patched/fdisk/fdisk.c	Wed Mar  1 14:36:06 2000
@@ -72,6 +72,9 @@
  * Sat Mar 20 09:31:05 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *	Internationalization
  *
+ * Wed Mar  1 14:34:53 EST 2000 David Huggins-Daines <dhuggins@linuxcare.com>
+ *      Better support for OSF/1 disklabels on Alpha.
+ *
  * Corrected deleting last logical partition -- aeb, 990430.
  * Removed all assumptions on file names -- aeb, 990709
  *   [modprobe gave ugly error messages, and the number of devices to probe
@@ -108,6 +111,7 @@
 #include "fdisksunlabel.h"
 #include "fdisksgilabel.h"
 #include "fdiskaixlabel.h"
+#include "fdiskbsdlabel.h"
 
 #include "../defines.h"
 #ifdef HAVE_blkpg_h
@@ -222,6 +226,7 @@
 int     sun_label = 0;                  /* looking at sun disklabel */
 int	sgi_label = 0;			/* looking at sgi disklabel */
 int	aix_label = 0;			/* looking at aix disklabel */
+int     osf_label = 0;                  /* looking at osf disklabel */
 
 struct	partition *part_table[MAXIMUM_PARTS]	/* partitions */
 		= {offset(buffer, 0), offset(buffer, 1),
@@ -517,7 +522,7 @@
 
 void warn_cylinders(void)
 {
-	if (!sun_label && !sgi_label && cylinders > 1024 && !nowarn)
+	if (!sun_label && !sgi_label && !osf_label && cylinders > 1024 && !nowarn)
 		fprintf(stderr, "\n\
 The number of cylinders for this disk is set to %d.\n\
 There is nothing wrong with that, but this is larger than 1024,\n\
@@ -686,12 +691,15 @@
 	if (check_aix_label())
 		return 0;
 
+	if (check_osf_label())
+		return 0;
+
 	if (!valid_part_table_flag(buffer)) {
 		switch(what) {
 		case fdisk:
 			fprintf(stderr,
 				_("Device contains neither a valid DOS partition"
-			 	  " table, nor Sun or SGI disklabel\n"));
+			 	  " table, nor Sun, SGI, or OSF disklabel\n"));
 #ifdef __sparc__
 			create_sunlabel();
 #else
@@ -1176,6 +1184,11 @@
 		return;
 	}
 
+	if (osf_label) {
+	        list_disk_geometry();
+		xbsd_print_disklabel(xtra);
+		return;
+	}
 	w = strlen(disk_device);
 	/* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
 	   but if the device name ends in a digit, say /dev/foo1,
@@ -1967,6 +1980,18 @@
 		fatal(usage2);
 
 	get_boot(fdisk);
+	/* On alpha, if we detect a disklabel, go directly to
+           disklabel mode (typically you'll be switching from DOS
+           partition tables to disklabels, not the other way around)
+           - dhuggins@linuxcare.com */
+#ifdef __alpha__
+	if (osf_label) {
+		printf(_("Detected an OSF/1 disklabel on %s, entering disklabel mode.\n"
+			 "To return to DOS partition table mode, use the 'r' command.\n"),
+		       disk_device);
+		bselect();
+	}
+#endif
 
 	while (1) {
 		putchar('\n');
diff --exclude=*~ -urN util-linux-2.10f/fdisk/fdiskbsdlabel.c util-linux-2.10f.patched/fdisk/fdiskbsdlabel.c
--- util-linux-2.10f/fdisk/fdiskbsdlabel.c	Thu Dec  9 09:29:21 1999
+++ util-linux-2.10f.patched/fdisk/fdiskbsdlabel.c	Wed Mar  1 14:37:10 2000
@@ -36,6 +36,10 @@
 
    Changes:
    19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
+
+   20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
+   support for OSF/1 disklabels on Alpha.  Also fixed unaligned
+   accesses in alpha_bootblock_checksum()
 */
 
 #include <unistd.h>
@@ -61,7 +65,6 @@
 
 static void xbsd_delete_part (void);
 static void xbsd_new_part (void);
-static void xbsd_print_disklabel (int show_all);
 static void xbsd_write_disklabel (void);
 static int xbsd_create_disklabel (void);
 static void xbsd_edit_disklabel (void);
@@ -84,7 +87,17 @@
 #endif
 
 static struct xbsd_disklabel xbsd_dlabel;
-static char buffer[BSD_BBSIZE];
+
+/* We need our own internal buffer because the disklabel lives
+   elsewhere on platforms that are damaged by DOS -
+   dhuggins@linuxcare.com */
+#if defined (__alpha__)
+/* Also, we access this through a u_int64_t * when checksumming */
+static char dlbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
+#else
+static char dlbuffer[BSD_BBSIZE];
+#endif
+
 #if defined (i386) || defined (__sparc__) || defined (__arm__)
 static struct partition *xbsd_part;
 static int xbsd_part_index;
@@ -99,6 +112,25 @@
     return 0;
 }
 
+int
+check_osf_label(void)
+{
+  extern void update_units(void);
+
+  if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
+    return 0;
+  osf_label = 1;
+  /* Get *correct* geometry info from the disklabel (otherwise disks
+     previously partitioned under Digital Unix won't work) -
+     dhuggins@linuxcare.com */
+  heads     = xbsd_dlabel.d_ntracks;
+  cylinders = xbsd_dlabel.d_ncylinders;
+  sectors   = xbsd_dlabel.d_nsectors;
+  update_units();
+
+  return 1;
+}
+
 void
 bmenu (void)
 {
@@ -111,11 +143,10 @@
   puts (_("   n   add a new BSD partition"));
   puts (_("   p   print BSD partition table"));
   puts (_("   q   quit without saving changes"));
-#if defined (i386) || defined (__sparc__) || defined (__arm__)
   puts (_("   r   return to main menu"));
-#endif
   puts (_("   s   show complete disklabel"));
   puts (_("   t   change a partition's filesystem id"));
+  puts (_("   u   change units (cylinders/sectors)"));
   puts (_("   w   write disklabel to disk"));
 #if defined (i386) || defined (__sparc__) || defined (__arm__)
   puts (_("   x   link BSD partition to non-BSD partition"));
@@ -134,6 +165,7 @@
 
 void
 bselect (void) {
+  extern void change_units(void);
 #if defined (i386) || defined (__sparc__) || defined (__arm__)
   int t, ss;
 
@@ -200,12 +232,15 @@
       case 't':
         xbsd_change_fstype ();
 	break;
+      case 'u':
+	change_units();
+	break;
       case 'w':
 	xbsd_write_disklabel ();
 	break;
-#if defined (i386) || defined (__sparc__) || defined (__arm__)
       case 'r':
 	return;
+#if defined (i386) || defined (__sparc__) || defined (__arm__)
       case 'x':
 	xbsd_link_part ();
 	break;
@@ -262,14 +297,14 @@
 		  cround (begin), mesg);
 
   if (display_in_cyl_units)
-    end = end * units_per_sector - 1;
+    end = (end - 1) * units_per_sector;
 
   xbsd_dlabel.d_partitions[i].p_size   = end - begin + 1;
   xbsd_dlabel.d_partitions[i].p_offset = begin;
-  xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; 
+  xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
 }
 
-static void
+void
 xbsd_print_disklabel (int show_all)
 {
   struct xbsd_disklabel *lp = &xbsd_dlabel;
@@ -321,12 +356,25 @@
       fprintf(f, "%ld ", (long) lp->d_drivedata[j]);
   }
   fprintf (f, _("\n%d partitions:\n"), lp->d_npartitions);
-  fprintf (f, _("#        size   offset    fstype   [fsize bsize   cpg]\n"));
+  fprintf (f, _("#       start       end      size     fstype   [fsize bsize   cpg]\n"));
   pp = lp->d_partitions;
   for (i = 0; i < lp->d_npartitions; i++, pp++) {
     if (pp->p_size) {
-      fprintf(f, "  %c: %8ld %8ld  ", 'a' + i,
-	      (long) pp->p_size, (long) pp->p_offset);
+      if (display_in_cyl_units) {
+	fprintf(f, "  %c: %8d%c %8d%c %8d%c  ", 'a' + i,
+		cround(pp->p_offset),
+		(pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
+		cround(pp->p_offset + pp->p_size - 1),
+		((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
+		pp->p_size / lp->d_secpercyl,
+		(pp->p_size % lp->d_secpercyl) ? '*' : ' ');
+		
+      } else {
+	fprintf(f, "  %c: %8d  %8d  %8d   ", 'a' + i,
+		pp->p_offset,
+		pp->p_offset + pp->p_size - 1,
+		pp->p_size);
+      }
       if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
 	fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name);
       else
@@ -348,27 +396,7 @@
 	  fprintf(f, "%20.20s", "");
 	  break;
       }
-      fprintf(f, "\t# (Cyl. %4ld", (long)
-#if 0
-	      pp->p_offset / lp->d_secpercyl); /* differs from Linux fdisk */
-#else
-	      pp->p_offset / lp->d_secpercyl + 1);
-#endif
-      if (pp->p_offset % lp->d_secpercyl)
-	putc('*', f);
-      else
-	putc(' ', f);
-      fprintf(f, "- %ld",
-	      (long) (pp->p_offset + 
-	       pp->p_size + lp->d_secpercyl - 1) /
-#if 0
-	      lp->d_secpercyl - 1); /* differs from Linux fdisk */
-#else
-	      lp->d_secpercyl);
-#endif
-      if (pp->p_size % lp->d_secpercyl)
-	putc('*', f);
-      fprintf(f, ")\n");
+      putc('\n', f);
     }
   }
 }
@@ -507,18 +535,18 @@
     dkbasename = line_ptr;
   }
   sprintf (path, "%s/%sboot", bootdir, dkbasename);
-  if (!xbsd_get_bootstrap (path, buffer, (int) xbsd_dlabel.d_secsize))
+  if (!xbsd_get_bootstrap (path, dlbuffer, (int) xbsd_dlabel.d_secsize))
     return;
 
   /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
-  d = &buffer[BSD_LABELSECTOR * SECTOR_SIZE];
+  d = &dlbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
   bcopy (d, &dl, sizeof (struct xbsd_disklabel));
 
   /* The disklabel will be overwritten by 0's from bootxx anyway */
   bzero (d, sizeof (struct xbsd_disklabel));
 
   sprintf (path, "%s/boot%s", bootdir, dkbasename);
-  if (!xbsd_get_bootstrap (path, &buffer[xbsd_dlabel.d_secsize],
+  if (!xbsd_get_bootstrap (path, &dlbuffer[xbsd_dlabel.d_secsize],
 			  (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
     return;
 
@@ -538,12 +566,12 @@
   sector = 0;
 #elif defined (__alpha__)
   sector = 0;
-  alpha_bootblock_checksum (buffer);
+  alpha_bootblock_checksum (dlbuffer);
 #endif
 
   if (ext2_llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
     fatal (unable_to_seek);
-  if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE))
+  if (BSD_BBSIZE != write (fd, dlbuffer, BSD_BBSIZE))
     fatal (unable_to_write);
 
 #if defined (i386) || defined (__sparc__) || defined (__arm__)
@@ -707,10 +735,10 @@
 
   if (ext2_llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
     fatal (unable_to_seek);
-  if (BSD_BBSIZE != read (fd, buffer, BSD_BBSIZE))
+  if (BSD_BBSIZE != read (fd, dlbuffer, BSD_BBSIZE))
     fatal (unable_to_read);
 
-  bcopy (&buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
+  bcopy (&dlbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
 	 d, sizeof (struct xbsd_disklabel));
 
   for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++)
@@ -745,14 +773,14 @@
   /* This is necessary if we want to write the bootstrap later,
      otherwise we'd write the old disklabel with the bootstrap.
   */
-  bcopy (d, &buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
+  bcopy (d, &dlbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
 	 sizeof (struct xbsd_disklabel));
 
 #if defined (__alpha__) && BSD_LABELSECTOR == 0
-  alpha_bootblock_checksum (buffer);
+  alpha_bootblock_checksum (dlbuffer);
   if (ext2_llseek (fd, 0, SEEK_SET) == -1)
     fatal (unable_to_seek);
-  if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE))
+  if (BSD_BBSIZE != write (fd, dlbuffer, BSD_BBSIZE))
     fatal (unable_to_write);
 #else
   if (ext2_llseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
diff --exclude=*~ -urN util-linux-2.10f/fdisk/fdiskbsdlabel.h util-linux-2.10f.patched/fdisk/fdiskbsdlabel.h
--- util-linux-2.10f/fdisk/fdiskbsdlabel.h	Fri Nov  5 11:59:06 1999
+++ util-linux-2.10f.patched/fdisk/fdiskbsdlabel.h	Wed Mar  1 14:00:51 2000
@@ -182,6 +182,7 @@
 #define	BSD_FS_BOOT	13		/* partition contains bootstrap */
 #define BSD_FS_ADOS	14		/* AmigaDOS fast file system */
 #define BSD_FS_HFS	15		/* Macintosh HFS */
+#define BSD_FS_ADVFS	16		/* Digital Unix AdvFS */
 
 /* this is annoying, but it's also the way it is :-( */
 #ifdef __alpha__
@@ -212,6 +213,7 @@
 	{BSD_FS_BOOT,   "boot"},
 	{BSD_FS_ADOS,   "ADOS"},
 	{BSD_FS_HFS,    "HFS"},
+	{BSD_FS_ADVFS,    "AdvFS"},
 	{ 0, NULL }
 };
 #define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
@@ -227,3 +229,8 @@
 #define	BSD_D_RAMDISK	0x08		/* disk emulator */
 #define	BSD_D_CHAIN    	0x10		/* can do back-back transfers */
 #define	BSD_D_DOSPART	0x20		/* within MSDOS partition */
+
+extern uint heads, sectors, cylinders;
+extern int osf_label;
+extern int check_osf_label(void);
+extern void xbsd_print_disklabel(int);
diff --exclude=*~ -urN util-linux-2.10f/po/cat-id-tbl.c util-linux-2.10f.patched/po/cat-id-tbl.c
--- util-linux-2.10f/po/cat-id-tbl.c	Wed Mar  1 10:26:44 2000
+++ util-linux-2.10f.patched/po/cat-id-tbl.c	Wed Mar  1 10:30:22 2000
@@ -841,7 +841,7 @@
   {"\
 \n\
 %d partitions:\n", 627},
-  {"#        size   offset    fstype   [fsize bsize   cpg]\n", 628},
+  {"#       start       end      size     fstype   [fsize bsize   cpg]\n", 628},
   {"Writing disklabel to %s%d.\n", 629},
   {"Writing disklabel to %s.\n", 630},
   {"%s%d contains no disklabel.\n", 631},


-- 
David Huggins-Daines, Senior Linux Consultant, Linuxcare, Inc.
613.562.1239 tel
dhuggins@linuxcare.com, http://www.linuxcare.com/
Linuxcare. Support for the revolution.


Reply to: