Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1170222 > unrolled thread

[PATCH RESEND] partitions/msdos: Support relative offset BSD partitions

Started byRoss Lagerwall <rosslagerwall@gmail.com>
First post2015-06-23 00:00 +0200
Last post2015-06-23 00:00 +0200
Articles 1 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH RESEND] partitions/msdos: Support relative offset BSD partitions Ross Lagerwall <rosslagerwall@gmail.com> - 2015-06-23 00:00 +0200

#1170222 — [PATCH RESEND] partitions/msdos: Support relative offset BSD partitions

FromRoss Lagerwall <rosslagerwall@gmail.com>
Date2015-06-23 00:00 +0200
Subject[PATCH RESEND] partitions/msdos: Support relative offset BSD partitions
Message-ID<pEhUZ-7PG-3@gated-at.bofh.it>
FreeBSD can use relative addressing for the offsets in its disklabel (it
appears that bsdlabel uses relative offsets and sysinstall uses absolute
offsets). When Linux reads the disklabel, either the partitions fail the
sanity checks and are considered invalid or they use the wrong offset
and data corruption ensues.

To fix this, determine if relative addressing is used by looking at
partition "c" in the disk label which is meant to represent the entire
slice. If "c" has an offset of 0, then relative addressing is used,
otherwise absolute addressing is used.

This change includes a cleanup to allow altering behavior based on the
type of disklabel.

The idea comes from the FreeBSD patch for GRUB:
http://lists.freebsd.org/pipermail/freebsd-ports-bugs/2010-November/201081.html

Signed-off-by: Ross Lagerwall <rosslagerwall@gmail.com>
---
 block/partitions/msdos.c | 33 ++++++++++++++++++++++++++-------
 include/linux/genhd.h    |  1 +
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c
index 93e7c1b..e8421c4 100644
--- a/block/partitions/msdos.c
+++ b/block/partitions/msdos.c
@@ -265,18 +265,30 @@ static void parse_solaris_x86(struct parsed_partitions *state,
 }
 
 #if defined(CONFIG_BSD_DISKLABEL)
+enum flavour {
+	FLAVOUR_BSD,
+	FLAVOUR_NETBSD,
+	FLAVOUR_OPENBSD,
+};
+
+static const char *const flavours[] = {
+	[FLAVOUR_BSD]		= "bsd",
+	[FLAVOUR_NETBSD]	= "netbsd",
+	[FLAVOUR_OPENBSD]	= "openbsd",
+};
 /*
  * Create devices for BSD partitions listed in a disklabel, under a
  * dos-like partition. See parse_extended() for more information.
  */
 static void parse_bsd(struct parsed_partitions *state,
-		      sector_t offset, sector_t size, int origin, char *flavour,
-		      int max_partitions)
+		      sector_t offset, sector_t size, int origin,
+		      enum flavour flavour, int max_partitions)
 {
 	Sector sect;
 	struct bsd_disklabel *l;
 	struct bsd_partition *p;
 	char tmp[64];
+	sector_t delta = 0;
 
 	l = read_part_sector(state, offset + 1, &sect);
 	if (!l)
@@ -286,11 +298,17 @@ static void parse_bsd(struct parsed_partitions *state,
 		return;
 	}
 
-	snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour);
+	snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin,
+		 flavours[flavour]);
 	strlcat(state->pp_buf, tmp, PAGE_SIZE);
 
 	if (le16_to_cpu(l->d_npartitions) < max_partitions)
 		max_partitions = le16_to_cpu(l->d_npartitions);
+	/* Determine if sector offsets are relative. */
+	if (BSD_WHOLE_DISK < le16_to_cpu(l->d_npartitions) &&
+	    flavour == FLAVOUR_BSD)
+		delta = offset -
+			le32_to_cpu(l->d_partitions[BSD_WHOLE_DISK].p_offset);
 	for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
 		sector_t bsd_start, bsd_size;
 
@@ -298,7 +316,7 @@ static void parse_bsd(struct parsed_partitions *state,
 			break;
 		if (p->p_fstype == BSD_FS_UNUSED)
 			continue;
-		bsd_start = le32_to_cpu(p->p_offset);
+		bsd_start = le32_to_cpu(p->p_offset) + delta;
 		bsd_size = le32_to_cpu(p->p_size);
 		if (offset == bsd_start && size == bsd_size)
 			/* full parent partition, we have it already */
@@ -323,7 +341,7 @@ static void parse_freebsd(struct parsed_partitions *state,
 			  sector_t offset, sector_t size, int origin)
 {
 #ifdef CONFIG_BSD_DISKLABEL
-	parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS);
+	parse_bsd(state, offset, size, origin, FLAVOUR_BSD, BSD_MAXPARTITIONS);
 #endif
 }
 
@@ -331,7 +349,8 @@ static void parse_netbsd(struct parsed_partitions *state,
 			 sector_t offset, sector_t size, int origin)
 {
 #ifdef CONFIG_BSD_DISKLABEL
-	parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS);
+	parse_bsd(state, offset, size, origin, FLAVOUR_NETBSD,
+		  BSD_MAXPARTITIONS);
 #endif
 }
 
@@ -339,7 +358,7 @@ static void parse_openbsd(struct parsed_partitions *state,
 			  sector_t offset, sector_t size, int origin)
 {
 #ifdef CONFIG_BSD_DISKLABEL
-	parse_bsd(state, offset, size, origin, "openbsd",
+	parse_bsd(state, offset, size, origin, FLAVOUR_OPENBSD,
 		  OPENBSD_MAXPARTITIONS);
 #endif
 }
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index ec274e0..d60bfdd 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -491,6 +491,7 @@ struct solaris_x86_vtoc {
 #define BSD_MAXPARTITIONS	16
 #define OPENBSD_MAXPARTITIONS	16
 #define BSD_FS_UNUSED		0	/* disklabel unused partition entry ID */
+#define BSD_WHOLE_DISK		2	/* partition representing entire disk */
 struct bsd_disklabel {
 	__le32	d_magic;		/* the magic number */
 	__s16	d_type;			/* drive type */
-- 
2.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [standalone]


Back to top | Article view | linux.kernel


csiph-web