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: