Skip site navigation (1)Skip section navigation (2)
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>