Date: Fri, 19 Nov 2010 02:04:30 GMT From: Andrey Zholos <aaz@althenia.net> To: freebsd-gnats-submit@FreeBSD.org Subject: ports/152389: sysutils/grub and sysutils/grub2 misinterpret disklabels created with bsdlabel Message-ID: <201011190204.oAJ24UDd052117@www.freebsd.org> Resent-Message-ID: <201011190210.oAJ2ADoh020524@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 152389 >Category: ports >Synopsis: sysutils/grub and sysutils/grub2 misinterpret disklabels created with bsdlabel >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-ports-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Nov 19 02:10:13 UTC 2010 >Closed-Date: >Last-Modified: >Originator: Andrey Zholos >Release: 8.1-STABLE >Organization: >Environment: >Description: Disklabels created by sysinstall (through libdisk) store partition offsets as absolute offsets (relative to the entire disk). Disklabels created by bsdlabel use relative offsets (relative to the enclosing slice) instead. The two variants are disambiguated by looking at the offset of the "c" partition, which should match the slice. GRUB assumes that offsets are absolute, so while it recognizes labels created by bsdlabel, it can't use them, because it reads at the wrong offset. This means that the GRUB root can't be placed on such partitions and that GRUB can't boot /boot/loader. bsdlabel keeps the offset scheme when it edits an existing label, so this problem is likely to only be encountered when partitioning a new disk manually (e.g. to move FreeBSD to a larger disk). >How-To-Repeat: To reproduce with GRUB 2 on a temporary memory disk: # mdconfig -a -t swap -s 256m md0 [ Substitute md0 in following commands ] # fdisk -I /dev/md0 [ Output omitted ] # bsdlabel -w /dev/md0s1 # bsdlabel -e /dev/md0s1 [ Change fstype of "a" from "unused" to "4.2BSD" and save ] # newfs /dev/md0s1a [ Output omitted ] # grub-probe -t fs -d /dev/md0s1a grub-probe: error: unknown filesystem. The correct output is: # grub-probe -t fs -d /dev/md0s1a ufs2 To reproduce with GRUB 1: [ Follow steps above, then: ] $ cat /usr/local/share/grub/i386-freebsd/stage{1,2} > grub_floppy $ qemu -hda /dev/md0 -fda grub_floppy -boot a [ At the GRUB prompt in the VM: ] grub> root (hd0,0,a) Filesystem type is unknown, partition type 0xa5 The correct output is: grub> root (hd0,0,a) Filesystem type is ufs2, partition type 0xa5 >Fix: The attached patch fixes the issue for GRUB 1 and 2 in ports. It assumes that there is a "c" partition covering the whole slice (this is what sys/geom/part/g_part_bsd.c does). GRUB 2 trunk has a similar fix (see discussion at [1]). [1] http://www.mail-archive.com/grub-devel@gnu.org/msg15595.html While I'm here, the patch also fixes UFS mounting in GRUB 1 for small partitions. Replace 256m with 16m in mdconfig above to test. Patch attached with submission follows: --- sysutils/grub/Makefile 2010-10-16 12:52:36.000000000 +0100 +++ sysutils/grub/Makefile 2010-11-18 14:20:01.000000000 +0000 @@ -7,7 +7,7 @@ PORTNAME= grub PORTVERSION= 0.97 -PORTREVISION= 4 +PORTREVISION= 5 CATEGORIES= sysutils MASTER_SITES= ftp://alpha.gnu.org/gnu/grub/ --- sysutils/grub/files/patch-bsd-partmap 1970-01-01 01:00:00.000000000 +0100 +++ sysutils/grub/files/patch-bsd-partmap 2010-11-18 14:07:11.000000000 +0000 @@ -0,0 +1,44 @@ +--- stage2/pc_slice.h 2003-07-09 12:45:53.000000000 +0100 ++++ stage2/pc_slice.h 2010-11-18 13:52:38.000000000 +0000 +@@ -168,6 +168,7 @@ + #define BSD_LABEL_MAG2_OFFSET 132 + #define BSD_LABEL_NPARTS_OFFSET 138 + #define BSD_LABEL_NPARTS_MAX 8 ++#define BSD_LABEL_RAW_PART 2 + + #define BSD_PART_OFFSET 148 + +--- stage2/disk_io.c 2004-05-23 17:35:24.000000000 +0100 ++++ stage2/disk_io.c 2010-11-18 14:06:53.000000000 +0000 +@@ -588,6 +588,7 @@ + { + int i; + int bsd_part_no = (*partition & 0xFF00) >> 8; ++ unsigned long raw_offset; + + /* If this is the first time... */ + if (bsd_part_no == 0xFF) +@@ -611,6 +612,23 @@ + return 0; + } + ++ /* Changle relative to absolute offsets in FreeBSD label. */ ++ if ((*type & 0xff) == PC_SLICE_TYPE_FREEBSD ++ && BSD_LABEL_RAW_PART < BSD_LABEL_NPARTS (buf)) ++ { ++ raw_offset = BSD_PART_START (buf, BSD_LABEL_RAW_PART); ++ for (i = 0; i < BSD_LABEL_NPARTS (buf); i++) ++ { ++ if (BSD_PART_START (buf, i) < raw_offset) ++ { ++ BSD_PART_TYPE (buf, i) = 0; ++ continue; ++ } ++ BSD_PART_START (buf, i) -= raw_offset; ++ BSD_PART_START (buf, i) += *start; ++ } ++ } ++ + bsd_part_no = -1; + } + --- sysutils/grub2/Makefile 2010-10-12 16:48:46.000000000 +0100 +++ sysutils/grub2/Makefile 2010-11-18 14:20:13.000000000 +0000 @@ -7,6 +7,7 @@ PORTNAME= grub2 PORTVERSION= 1.98 +PORTREVISION= 1 CATEGORIES= sysutils MASTER_SITES= ftp://alpha.gnu.org/gnu/grub/ DISTNAME= grub-${PORTVERSION} --- sysutils/grub2/files/patch-bsd-partmap 1970-01-01 01:00:00.000000000 +0100 +++ sysutils/grub2/files/patch-bsd-partmap 2010-11-17 20:16:54.000000000 +0000 @@ -0,0 +1,47 @@ +--- include/grub/msdos_partition.h 2010-03-06 20:51:37.000000000 +0000 ++++ include/grub/msdos_partition.h 2010-11-17 18:22:29.000000000 +0000 +@@ -57,6 +57,7 @@ + #define GRUB_PC_PARTITION_BSD_LABEL_SECTOR 1 + #define GRUB_PC_PARTITION_BSD_LABEL_MAGIC 0x82564557 + #define GRUB_PC_PARTITION_BSD_MAX_ENTRIES 8 ++#define GRUB_PC_PARTITION_BSD_RAW_PART 2 + + /* BSD partition types. */ + #define GRUB_PC_PARTITION_BSD_TYPE_UNUSED 0 +--- partmap/msdos.c 2010-03-06 20:51:37.000000000 +0000 ++++ partmap/msdos.c 2010-11-17 18:26:26.000000000 +0000 +@@ -176,6 +176,8 @@ + /* Check if this is a BSD partition. */ + if (grub_msdos_partition_is_bsd (e->type)) + { ++ grub_uint32_t slice_offset = 0, raw_offset = 0; ++ + /* Check if the BSD label is within the DOS partition. */ + if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR) + { +@@ -200,6 +202,15 @@ + label.magic, p.index); + continue; + } ++ ++ /* Compensate for relative addressing in FreeBSD. */ ++ if (e->type == GRUB_PC_PARTITION_TYPE_FREEBSD ++ && GRUB_PC_PARTITION_BSD_RAW_PART < grub_cpu_to_le16 (label.num_partitions)) ++ { ++ slice_offset = p.start; ++ raw_offset = grub_le_to_cpu32 (label.entries[GRUB_PC_PARTITION_BSD_RAW_PART].offset); ++ } ++ + for (pcdata.bsd_part = 0; + pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions); + pcdata.bsd_part++) +@@ -207,7 +218,9 @@ + struct grub_msdos_partition_bsd_entry *be + = label.entries + pcdata.bsd_part; + ++ if (grub_le_to_cpu32 (be->offset) < raw_offset) ++ continue; +- p.start = grub_le_to_cpu32 (be->offset); ++ p.start = grub_le_to_cpu32 (be->offset) - raw_offset + slice_offset; + p.len = grub_le_to_cpu32 (be->size); + pcdata.bsd_type = be->fs_type; --- sysutils/grub/files/patch-stage2-fsys__ufs2.c 1970-01-01 01:00:00.000000000 +0100 +++ sysutils/grub/files/patch-stage2-fsys__ufs2.c 2010-11-18 19:06:59.000000000 +0000 @@ -0,0 +1,11 @@ +--- stage2/fsys_ufs2.c 2004-06-19 13:17:52.000000000 +0100 ++++ stage2/fsys_ufs2.c 2010-11-18 19:00:24.000000000 +0000 +@@ -92,8 +92,8 @@ + { + for (i = 0; sblock_try[i] != -1; ++i) + { +- if (! (part_length < (sblock_try[i] + (SBLOCKSIZE / DEV_BSIZE)) ++ if (! (part_length < ((sblock_try[i] + SBLOCKSIZE) / DEV_BSIZE) + || ! devread (0, sblock_try[i], SBLOCKSIZE, (char *) SUPERBLOCK))) + { + if (SUPERBLOCK->fs_magic == FS_UFS2_MAGIC /* && >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201011190204.oAJ24UDd052117>