Source-Changes-HG archive

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

[src/trunk]: src/sys/ufs/lfs Enable mounting lfs64 volumes.



details:   https://anonhg.NetBSD.org/src/rev/07ea9d2fc643
branches:  trunk
changeset: 341035:07ea9d2fc643
user:      dholland <dholland%NetBSD.org@localhost>
date:      Thu Oct 15 06:25:34 2015 +0000

description:
Enable mounting lfs64 volumes.

diffstat:

 sys/ufs/lfs/lfs_vfsops.c |  215 +++++++++++++++++++++++++++++++---------------
 1 files changed, 142 insertions(+), 73 deletions(-)

diffs (truncated from 335 to 300 lines):

diff -r 9cd2ee0ed933 -r 07ea9d2fc643 sys/ufs/lfs/lfs_vfsops.c
--- a/sys/ufs/lfs/lfs_vfsops.c  Thu Oct 15 06:25:23 2015 +0000
+++ b/sys/ufs/lfs/lfs_vfsops.c  Thu Oct 15 06:25:34 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_vfsops.c,v 1.347 2015/10/15 06:15:48 dholland Exp $        */
+/*     $NetBSD: lfs_vfsops.c,v 1.348 2015/10/15 06:25:34 dholland Exp $        */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007, 2007
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.347 2015/10/15 06:15:48 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.348 2015/10/15 06:25:34 dholland Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_lfs.h"
@@ -829,6 +829,38 @@
        return (error);
 }
 
+/*
+ * Helper for mountfs. Note that the fs pointer may be a dummy one
+ * pointing into a superblock buffer. (Which is gross; see below.)
+ */
+static int
+lfs_checkmagic(struct lfs *fs)
+{
+       switch (fs->lfs_dlfs_u.u_32.dlfs_magic) {
+           case LFS_MAGIC:
+               fs->lfs_is64 = false;
+               fs->lfs_dobyteswap = false;
+               break;
+           case LFS64_MAGIC:
+               fs->lfs_is64 = true;
+               fs->lfs_dobyteswap = false;
+               break;
+#ifdef LFS_EI
+           case LFS_MAGIC_SWAPPED:
+               fs->lfs_is64 = false;
+               fs->lfs_dobyteswap = true;
+               break;
+           case LFS64_MAGIC_SWAPPED:
+               fs->lfs_is64 = true;
+               fs->lfs_dobyteswap = true;
+               break;
+#endif
+           default:
+               /* XXX needs translation */
+               return EINVAL;
+       }
+       return 0;
+}
 
 /*
  * Common code for mount and mountroot
@@ -837,11 +869,11 @@
 int
 lfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
 {
-       struct dlfs *tdfs, *dfs, *adfs;
+       struct lfs *primarysb, *altsb, *thesb;
+       struct buf *primarybuf, *altbuf;
        struct lfs *fs;
        struct ulfsmount *ump;
        struct vnode *vp;
-       struct buf *bp, *abp;
        dev_t dev;
        int error, i, ronly, fsbsize;
        kauth_cred_t cred;
@@ -866,49 +898,65 @@
        ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
 
        /* Don't free random space on error. */
-       bp = NULL;
-       abp = NULL;
+       primarybuf = NULL;
+       altbuf = NULL;
        ump = NULL;
 
        sb_addr = LFS_LABELPAD / DEV_BSIZE;
        while (1) {
-               /* Read in the superblock. */
-               error = bread(devvp, sb_addr, LFS_SBPAD, 0, &bp);
+               /*
+                * Read in the superblock.
+                *
+                * Note that because LFS_SBPAD is substantially larger
+                * (8K) than the actual on-disk superblock (512 bytes)
+                * the buffer contains enough space to be used as a
+                * whole struct lfs (in-memory superblock) - we do this
+                * only so we can set and use the is64 and dobyteswap
+                * members. XXX this is gross and the logic here should
+                * be reworked.
+                */
+               error = bread(devvp, sb_addr, LFS_SBPAD, 0, &primarybuf);
                if (error)
                        goto out;
-               dfs = (struct dlfs *)bp->b_data;
+               primarysb = (struct lfs *)primarybuf->b_data;
 
                /* Check the basics. */
-               if (dfs->dlfs_magic != LFS_MAGIC || dfs->dlfs_bsize > MAXBSIZE ||
-                   dfs->dlfs_version > LFS_VERSION ||
-                   dfs->dlfs_bsize < sizeof(struct dlfs)) {
-                       DLOG((DLOG_MOUNT, "lfs_mountfs: primary superblock sanity failed\n"));
-                       error = EINVAL;         /* XXX needs translation */
+               error = lfs_checkmagic(primarysb);
+               if (error) {
+                       DLOG((DLOG_MOUNT, "lfs_mountfs: primary superblock wrong magic\n"));
                        goto out;
                }
-               if (dfs->dlfs_inodefmt > LFS_MAXINODEFMT) {
+               if (lfs_sb_getbsize(primarysb) > MAXBSIZE ||
+                   lfs_sb_getversion(primarysb) > LFS_VERSION ||
+                   lfs_sb_getbsize(primarysb) < sizeof(struct dlfs)) {
+                       DLOG((DLOG_MOUNT, "lfs_mountfs: primary superblock sanity failed\n"));
+                       /* XXX needs translation */
+                       error = EINVAL;
+                       goto out;
+               }
+               if (lfs_sb_getinodefmt(primarysb) > LFS_MAXINODEFMT) {
                        DLOG((DLOG_MOUNT, "lfs_mountfs: unknown inode format %d\n",
-                              dfs->dlfs_inodefmt));
+                              lfs_sb_getinodefmt(primarysb)));
                        error = EINVAL;
                        goto out;
                }
 
-               if (dfs->dlfs_version == 1)
+               if (lfs_sb_getversion(primarysb) == 1)
                        fsbsize = DEV_BSIZE;
                else {
-                       fsbsize = 1 << dfs->dlfs_ffshift;
+                       fsbsize = 1 << lfs_sb_getffshift(primarysb);
                        /*
                         * Could be, if the frag size is large enough, that we
                         * don't have the "real" primary superblock.  If that's
                         * the case, get the real one, and try again.
                         */
-                       if (sb_addr != (dfs->dlfs_sboffs[0] << (dfs->dlfs_ffshift - DEV_BSHIFT))) {
+                       if (sb_addr != (lfs_sb_getsboff(primarysb, 0) << (lfs_sb_getffshift(primarysb) - DEV_BSHIFT))) {
                                DLOG((DLOG_MOUNT, "lfs_mountfs: sb daddr"
                                      " 0x%llx is not right, trying 0x%llx\n",
                                      (long long)sb_addr,
-                                     (long long)(dfs->dlfs_sboffs[0] << (dfs->dlfs_ffshift - DEV_BSHIFT))));
-                               sb_addr = dfs->dlfs_sboffs[0] << (dfs->dlfs_ffshift - DEV_BSHIFT);
-                               brelse(bp, 0);
+                                     (long long)(lfs_sb_getsboff(primarysb, 0) << (lfs_sb_getffshift(primarysb) - DEV_BSHIFT))));
+                               sb_addr = lfs_sb_getsboff(primarysb, 0) << (lfs_sb_getffshift(primarysb) - DEV_BSHIFT);
+                               brelse(primarybuf, BC_INVAL);
                                continue;
                        }
                }
@@ -921,51 +969,68 @@
         * the filesystem is valid if it was not unmounted cleanly.
         */
 
-       if (dfs->dlfs_sboffs[1] &&
-           dfs->dlfs_sboffs[1] - LFS_LABELPAD / fsbsize > LFS_SBPAD / fsbsize)
+       if (lfs_sb_getsboff(primarysb, 1) &&
+           lfs_sb_getsboff(primarysb, 1) - LFS_LABELPAD / fsbsize > LFS_SBPAD / fsbsize)
        {
-               error = bread(devvp, dfs->dlfs_sboffs[1] * (fsbsize / DEV_BSIZE),
-                       LFS_SBPAD, 0, &abp);
+               error = bread(devvp, lfs_sb_getsboff(primarysb, 1) * (fsbsize / DEV_BSIZE),
+                       LFS_SBPAD, 0, &altbuf);
                if (error)
                        goto out;
-               adfs = (struct dlfs *)abp->b_data;
+               altsb = (struct lfs *)altbuf->b_data;
 
-               if (dfs->dlfs_version == 1) {
-                       /* 1s resolution comparison */
-                       if (adfs->dlfs_tstamp < dfs->dlfs_tstamp)
-                               tdfs = adfs;
-                       else
-                               tdfs = dfs;
-               } else {
-                       /* monotonic infinite-resolution comparison */
-                       if (adfs->dlfs_serial < dfs->dlfs_serial)
-                               tdfs = adfs;
-                       else
-                               tdfs = dfs;
-               }
+               /*
+                * Note: this used to do the sanity check only if the
+                * timestamp/serial comparison required use of altsb;
+                * this way is less tolerant, but if altsb is corrupted
+                * enough that the magic number, version, and blocksize
+                * are bogus, why would the timestamp or serial fields
+                * mean anything either? If this kind of thing happens,
+                * you need to fsck anyway.
+                */
+
+               error = lfs_checkmagic(altsb);
+               if (error)
+                       goto out;
 
                /* Check the basics. */
-               if (tdfs->dlfs_magic != LFS_MAGIC ||
-                   tdfs->dlfs_bsize > MAXBSIZE ||
-                   tdfs->dlfs_version > LFS_VERSION ||
-                   tdfs->dlfs_bsize < sizeof(struct dlfs)) {
+               if (lfs_sb_getbsize(altsb) > MAXBSIZE ||
+                   lfs_sb_getversion(altsb) > LFS_VERSION ||
+                   lfs_sb_getbsize(altsb) < sizeof(struct dlfs)) {
                        DLOG((DLOG_MOUNT, "lfs_mountfs: alt superblock"
                              " sanity failed\n"));
                        error = EINVAL;         /* XXX needs translation */
                        goto out;
                }
+
+               if (lfs_sb_getversion(primarysb) == 1) {
+                       /* 1s resolution comparison */
+                       if (lfs_sb_gettstamp(altsb) < lfs_sb_gettstamp(primarysb))
+                               thesb = altsb;
+                       else
+                               thesb = primarysb;
+               } else {
+                       /* monotonic infinite-resolution comparison */
+                       if (lfs_sb_getserial(altsb) < lfs_sb_getserial(primarysb))
+                               thesb = altsb;
+                       else
+                               thesb = primarysb;
+               }
        } else {
-               DLOG((DLOG_MOUNT, "lfs_mountfs: invalid alt superblock"
-                     " daddr=0x%x\n", dfs->dlfs_sboffs[1]));
+               DLOG((DLOG_MOUNT, "lfs_mountfs: invalid alt superblock location"
+                     " daddr=0x%x\n", lfs_sb_getsboff(primarysb, 1)));
                error = EINVAL;
                goto out;
        }
 
-       /* Allocate the mount structure, copy the superblock into it. */
+       /*
+        * Allocate the mount structure, copy the superblock into it.
+        * Note that the 32-bit and 64-bit superblocks are the same size.
+        */
        fs = kmem_zalloc(sizeof(struct lfs), KM_SLEEP);
-       memcpy(&fs->lfs_dlfs_u.u_32, tdfs, sizeof(struct dlfs));
-       fs->lfs_is64 = false; /* XXX notyet */
-       fs->lfs_dobyteswap = false; /* XXX notyet */
+       memcpy(&fs->lfs_dlfs_u.u_32, &thesb->lfs_dlfs_u.u_32,
+              sizeof(struct dlfs));
+       fs->lfs_is64 = thesb->lfs_is64;
+       fs->lfs_dobyteswap = thesb->lfs_dobyteswap;
        fs->lfs_hasolddirfmt = false; /* set for real below */
 
        /* Compatibility */
@@ -1005,15 +1070,10 @@
        ump->um_lfs = fs;
        ump->um_fstype = ULFS1;
        /* ump->um_cleaner_thread = NULL; */
-       if (sizeof(struct lfs) < LFS_SBPAD) {                   /* XXX why? */
-               brelse(bp, BC_INVAL);
-               brelse(abp, BC_INVAL);
-       } else {
-               brelse(bp, 0);
-               brelse(abp, 0);
-       }
-       bp = NULL;
-       abp = NULL;
+       brelse(primarybuf, BC_INVAL);
+       brelse(altbuf, BC_INVAL);
+       primarybuf = NULL;
+       altbuf = NULL;
 
 
        /* Set up the I/O information */
@@ -1122,6 +1182,7 @@
        memset(fs->lfs_suflags[1], 0, lfs_sb_getnseg(fs) * sizeof(u_int32_t));
        for (i = 0; i < lfs_sb_getnseg(fs); i++) {
                int changed;
+               struct buf *bp;
 
                LFS_SEGENTRY(sup, fs, i, bp);
                changed = 0;
@@ -1218,21 +1279,29 @@
         * Initialize the ifile cleaner info with information from
         * the superblock.
         */
-       LFS_CLEANERINFO(cip, fs, bp);
-       lfs_ci_setclean(fs, cip, lfs_sb_getnclean(fs));
-       lfs_ci_setdirty(fs, cip, lfs_sb_getnseg(fs) - lfs_sb_getnclean(fs));
-       lfs_ci_setavail(fs, cip, lfs_sb_getavail(fs));
-       lfs_ci_setbfree(fs, cip, lfs_sb_getbfree(fs));
-       (void) LFS_BWRITE_LOG(bp); /* Ifile */
+       {
+               struct buf *bp;
+
+               LFS_CLEANERINFO(cip, fs, bp);
+               lfs_ci_setclean(fs, cip, lfs_sb_getnclean(fs));
+               lfs_ci_setdirty(fs, cip, lfs_sb_getnseg(fs) - lfs_sb_getnclean(fs));
+               lfs_ci_setavail(fs, cip, lfs_sb_getavail(fs));
+               lfs_ci_setbfree(fs, cip, lfs_sb_getbfree(fs));
+               (void) LFS_BWRITE_LOG(bp); /* Ifile */
+       }



Home | Main Index | Thread Index | Old Index