Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src PR kern/51208



details:   https://anonhg.NetBSD.org/src/rev/3ac1a7bfd919
branches:  trunk
changeset: 351590:3ac1a7bfd919
user:      rin <rin%NetBSD.org@localhost>
date:      Sun Feb 19 07:43:42 2017 +0000

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

diffstat:

 share/man/man4/options.4 |   31 +++++++++-
 sys/kern/subr_disk_mbr.c |  141 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 166 insertions(+), 6 deletions(-)

diffs (262 lines):

diff -r cb0523d07cd0 -r 3ac1a7bfd919 share/man/man4/options.4
--- a/share/man/man4/options.4  Sun Feb 19 02:11:19 2017 +0000
+++ b/share/man/man4/options.4  Sun Feb 19 07:43:42 2017 +0000
@@ -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 @@
 .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
diff -r cb0523d07cd0 -r 3ac1a7bfd919 sys/kern/subr_disk_mbr.c
--- a/sys/kern/subr_disk_mbr.c  Sun Feb 19 02:11:19 2017 +0000
+++ b/sys/kern/subr_disk_mbr.c  Sun Feb 19 07:43:42 2017 +0000
@@ -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 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 @@
 }
 
 
+#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 @@
                        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 @@
 
        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 @@
                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 @@
        }
 
        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 @@
 
        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 */



Home | Main Index | Thread Index | Old Index