All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RESEND] partitions/msdos: Support relative offset BSD partitions
@ 2015-06-22 21:52 Ross Lagerwall
  0 siblings, 0 replies; only message in thread
From: Ross Lagerwall @ 2015-06-22 21:52 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jens Axboe, Fabian Frederick, Ross Lagerwall

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/

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2015-06-22 21:52 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-22 21:52 [PATCH RESEND] partitions/msdos: Support relative offset BSD partitions Ross Lagerwall

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.