Module Name:    src
Committed By:   rin
Date:           Sun Feb 19 07:43:42 UTC 2017

Modified Files:
        src/share/man/man4: options.4
        src/sys/kern: subr_disk_mbr.c

Log Message:
PR kern/51208
Add DISKLABEL_EI (``Endian-Independent'' disklabel) kernel option to machines
that support Master Boot Record (MBR)


To generate a diff of this commit:
cvs rdiff -u -r1.461 -r1.462 src/share/man/man4/options.4
cvs rdiff -u -r1.46 -r1.47 src/sys/kern/subr_disk_mbr.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/options.4
diff -u src/share/man/man4/options.4:1.461 src/share/man/man4/options.4:1.462
--- src/share/man/man4/options.4:1.461	Mon Feb 13 09:46:29 2017
+++ src/share/man/man4/options.4	Sun Feb 19 07:43:42 2017
@@ -1,4 +1,4 @@
-.\"	$NetBSD: options.4,v 1.461 2017/02/13 09:46:29 skrll Exp $
+.\"	$NetBSD: options.4,v 1.462 2017/02/19 07:43:42 rin Exp $
 .\"
 .\" Copyright (c) 1996
 .\" 	Perry E. Metzger.  All rights reserved.
@@ -30,7 +30,7 @@
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\"
-.Dd January 8, 2017
+.Dd February 19, 2017
 .Dt OPTIONS 4
 .Os
 .Sh NAME
@@ -971,6 +971,33 @@ This enables for example sshfs:
 .El
 .Ss File System Options
 .Bl -ohang
+.It Cd options DISKLABEL_EI
+Enable
+.Dq Endian-Independent
+.Xr disklabel 5
+support.
+This allows a system to recognize a disklabel written in the other byte order.
+For writing, when a label already exists, its byte order is preserved.
+Otherwise, a new label is written in the native byte order.
+To specify the byte order explicitly,
+.Fl F
+option of
+.Xr disklabel 8
+should be used with
+.Fl B
+option in order to avoid using
+.Xr ioctl 2 ,
+which results in the default behavior explained above.
+At the moment this option is restricted to the following ports:
+amd64, bebox, emips, epoc32, evbarm, i386, ibmnws, landisk, mvmeppc, prep,
+.\" riscv,
+rs6000, sandpoint,
+.\" usermode,
+xen, and zaurus.
+And to machines of
+.\" evbarm64,
+evbmips and evbppc ports that support
+Master Boot Record (MBR).
 .It Cd options MAGICLINKS
 Enables the expansion of special strings
 .Po

Index: src/sys/kern/subr_disk_mbr.c
diff -u src/sys/kern/subr_disk_mbr.c:1.46 src/sys/kern/subr_disk_mbr.c:1.47
--- src/sys/kern/subr_disk_mbr.c:1.46	Wed Jun 26 18:47:26 2013
+++ src/sys/kern/subr_disk_mbr.c	Sun Feb 19 07:43:42 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_disk_mbr.c,v 1.46 2013/06/26 18:47:26 matt Exp $	*/
+/*	$NetBSD: subr_disk_mbr.c,v 1.47 2017/02/19 07:43:42 rin Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_disk_mbr.c,v 1.46 2013/06/26 18:47:26 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_disk_mbr.c,v 1.47 2017/02/19 07:43:42 rin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -117,6 +117,10 @@ static int validate_label(mbr_args_t *, 
 static int look_netbsd_part(mbr_args_t *, mbr_partition_t *, int, uint);
 static int write_netbsd_label(mbr_args_t *, mbr_partition_t *, int, uint);
 
+#ifdef DISKLABEL_EI
+static void swap_disklabel(struct disklabel *, struct disklabel *);
+#endif
+
 static int
 read_sector(mbr_args_t *a, uint sector, int count)
 {
@@ -565,12 +569,23 @@ look_netbsd_part(mbr_args_t *a, mbr_part
 }
 
 
+#ifdef DISKLABEL_EI
+/*
+ * - For read, convert a label to the native byte order.
+ * - For update or write, if a label already exists, keep its byte order.
+ *   Otherwise, write a new label in the native byte order.
+ */
+#endif
 static int
 validate_label(mbr_args_t *a, uint label_sector)
 {
 	struct disklabel *dlp;
 	char *dlp_lim, *dlp_byte;
 	int error;
+#ifdef DISKLABEL_EI
+	int swapped = 0;
+	uint16_t npartitions;
+#endif
 
 	/* Next, dig out disk label */
 	if (read_sector(a, label_sector, SCANBLOCKS)) {
@@ -603,8 +618,31 @@ validate_label(mbr_args_t *a, uint label
 			break;
 		}
 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
+#ifdef DISKLABEL_EI
+		{
+			if (bswap32(dlp->d_magic)  != DISKMAGIC ||
+			    bswap32(dlp->d_magic2) != DISKMAGIC)
+				continue;
+
+			/*
+			 * The label is in the other byte order. We need to
+			 * checksum before swapping the byte order.
+			 */
+			npartitions = bswap16(dlp->d_npartitions);
+			if (npartitions > MAXPARTITIONS ||
+			    dkcksum_sized(dlp, npartitions) != 0)
+				goto corrupted;
+
+			swapped = 1;
+		}
+#else
 			continue;
-		if (dlp->d_npartitions > MAXPARTITIONS || dkcksum(dlp) != 0) {
+#endif
+		else if (dlp->d_npartitions > MAXPARTITIONS ||
+			 dkcksum(dlp) != 0) {
+#ifdef DISKLABEL_EI
+corrupted:
+#endif
 			a->msg = "disk label corrupted";
 			continue;
 		}
@@ -613,7 +651,14 @@ validate_label(mbr_args_t *a, uint label
 
 	switch (a->action) {
 	case READ_LABEL:
+#ifdef DISKLABEL_EI
+		if (swapped)
+			swap_disklabel(a->lp, dlp);
+		else
+			*a->lp = *dlp;
+#else
 		*a->lp = *dlp;
+#endif
 		if ((a->msg = convertdisklabel(a->lp, a->strat, a->bp,
 		                              a->secperunit)) != NULL)
 			return SCAN_ERROR;
@@ -621,7 +666,15 @@ validate_label(mbr_args_t *a, uint label
 		return SCAN_FOUND;
 	case UPDATE_LABEL:
 	case WRITE_LABEL:
+#ifdef DISKLABEL_EI
+		/* DO NOT swap a->lp itself for later references. */
+		if (swapped)
+			swap_disklabel(dlp, a->lp);
+		else
+			*dlp = *a->lp;
+#else
 		*dlp = *a->lp;
+#endif
 		a->bp->b_oflags &= ~BO_DONE;
 		a->bp->b_flags &= ~B_READ;
 		a->bp->b_flags |= B_WRITE;
@@ -663,7 +716,7 @@ setdisklabel(struct disklabel *olp, stru
 	}
 
 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
-	    dkcksum(nlp) != 0)
+	    nlp->d_npartitions > MAXPARTITIONS || dkcksum(nlp) != 0)
 		return (EINVAL);
 
 	/* XXX missing check if other dos partitions will be overwritten */
@@ -738,3 +791,83 @@ write_netbsd_label(mbr_args_t *a, mbr_pa
 
 	return validate_label(a, ptn_base);
 }
+
+#ifdef DISKLABEL_EI
+/*
+ * from sh3/disksubr.c with modifications:
+ *	- update d_checksum properly
+ *	- replace memcpy(9) by memmove(9) as a precaution
+ */
+static void
+swap_disklabel(struct disklabel *nlp, struct disklabel *olp)
+{
+	int i;
+	uint16_t npartitions;
+
+#define	SWAP16(x)	nlp->x = bswap16(olp->x)
+#define	SWAP32(x)	nlp->x = bswap32(olp->x)
+
+	SWAP32(d_magic);
+	SWAP16(d_type);
+	SWAP16(d_subtype);
+	/* Do not need to swap char strings. */
+	memmove(nlp->d_typename, olp->d_typename, sizeof(nlp->d_typename));
+
+	/* XXX What should we do for d_un (an union of char and pointers) ? */
+	memmove(nlp->d_packname, olp->d_packname, sizeof(nlp->d_packname));
+
+	SWAP32(d_secsize);
+	SWAP32(d_nsectors);
+	SWAP32(d_ntracks);
+	SWAP32(d_ncylinders);
+	SWAP32(d_secpercyl);
+	SWAP32(d_secperunit);
+
+	SWAP16(d_sparespertrack);
+	SWAP16(d_sparespercyl);
+
+	SWAP32(d_acylinders);
+
+	SWAP16(d_rpm);
+	SWAP16(d_interleave);
+	SWAP16(d_trackskew);
+	SWAP16(d_cylskew);
+	SWAP32(d_headswitch);
+	SWAP32(d_trkseek);
+	SWAP32(d_flags);
+	for (i = 0; i < NDDATA; i++)
+		SWAP32(d_drivedata[i]);
+	for (i = 0; i < NSPARE; i++)
+		SWAP32(d_spare[i]);
+	SWAP32(d_magic2);
+	/* d_checksum is updated later. */
+
+	SWAP16(d_npartitions);
+	SWAP32(d_bbsize);
+	SWAP32(d_sbsize);
+	for (i = 0; i < MAXPARTITIONS; i++) {
+		SWAP32(d_partitions[i].p_size);
+		SWAP32(d_partitions[i].p_offset);
+		SWAP32(d_partitions[i].p_fsize);
+		/* p_fstype and p_frag is uint8_t, so no need to swap. */
+		nlp->d_partitions[i].p_fstype = olp->d_partitions[i].p_fstype;
+		nlp->d_partitions[i].p_frag = olp->d_partitions[i].p_frag;
+		SWAP16(d_partitions[i].p_cpg);
+	}
+
+#undef SWAP16
+#undef SWAP32
+
+	/* Update checksum in the target endian. */
+	nlp->d_checksum = 0;
+	npartitions = nlp->d_magic == DISKMAGIC ?
+	    nlp->d_npartitions : olp->d_npartitions;
+	/*
+	 * npartitions can be larger than MAXPARTITIONS when the label was not
+	 * validated by setdisklabel. If so, the label is intentionally(?)
+	 * corrupted and checksum should be meaningless.
+	 */
+	if (npartitions <= MAXPARTITIONS)
+		nlp->d_checksum = dkcksum_sized(nlp, npartitions);
+}
+#endif /* DISKLABEL_EI */

Reply via email to