Author: marcel
Date: Sat Oct  2 19:44:13 2010
New Revision: 213365
URL: http://svn.freebsd.org/changeset/base/213365

Log:
  Split the root mount logic from the (generic) mount code and move
  it (the root mount code) into a new file called vfs_mountroot.c
  
  The split is almost trivial, as the code is almost perfectly
  non-intertwined. The only adjustment needed was to move the UMA
  zone allocation out of vfs_mountroot() [in vfs_mountroot.c] and
  into vfs_mount.c, where it had to be done as a SYSINIT [see
  vfs_mount_init()].
  
  There are no functional changes with this commit.

Added:
  head/sys/kern/vfs_mountroot.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/kern/vfs_mount.c

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Sat Oct  2 18:53:12 2010        (r213364)
+++ head/sys/conf/files Sat Oct  2 19:44:13 2010        (r213365)
@@ -2264,6 +2264,7 @@ kern/vfs_hash.c                   standard
 kern/vfs_init.c                        standard
 kern/vfs_lookup.c              standard
 kern/vfs_mount.c               standard
+kern/vfs_mountroot.c           standard
 kern/vfs_subr.c                        standard
 kern/vfs_syscalls.c            standard
 kern/vfs_vnops.c               standard

Modified: head/sys/kern/vfs_mount.c
==============================================================================
--- head/sys/kern/vfs_mount.c   Sat Oct  2 18:53:12 2010        (r213364)
+++ head/sys/kern/vfs_mount.c   Sat Oct  2 19:44:13 2010        (r213365)
@@ -67,16 +67,10 @@ __FBSDID("$FreeBSD$");
 #include <security/audit/audit.h>
 #include <security/mac/mac_framework.h>
 
-#include "opt_rootdevname.h"
-
-#define        ROOTNAME                "root_device"
 #define        VFS_MOUNTARG_SIZE_MAX   (1024 * 64)
 
-static void    set_rootvnode(void);
 static int     vfs_domount(struct thread *td, const char *fstype,
                    char *fspath, int fsflags, void *fsdata);
-static int     vfs_mountroot_ask(void);
-static int     vfs_mountroot_try(const char *mountfrom, const char *options);
 static void    free_mntarg(struct mntarg *ma);
 
 static int     usermount = 0;
@@ -95,31 +89,6 @@ struct mtx mountlist_mtx;
 MTX_SYSINIT(mountlist, &mountlist_mtx, "mountlist", MTX_DEF);
 
 /*
- * The vnode of the system's root (/ in the filesystem, without chroot
- * active.)
- */
-struct vnode   *rootvnode;
-
-/*
- * The root filesystem is detailed in the kernel environment variable
- * vfs.root.mountfrom, which is expected to be in the general format
- *
- * <vfsname>:[<path>][ <vfsname>:[<path>] ...]
- * vfsname   := the name of a VFS known to the kernel and capable
- *              of being mounted as root
- * path      := disk device name or other data used by the filesystem
- *              to locate its physical store
- *
- * If the environment variable vfs.root.mountfrom is a space separated list,
- * each list element is tried in turn and the root filesystem will be mounted
- * from the first one that suceeds.
- *
- * The environment variable vfs.root.mountfrom.options is a comma delimited
- * set of string mount options.  These mount options must be parseable
- * by nmount() in the kernel.
- */
-
-/*
  * Global opts, taken by all filesystems
  */
 static const char *global_opts[] = {
@@ -133,21 +102,35 @@ static const char *global_opts[] = {
        NULL
 };
 
-/*
- * The root specifiers we will try if RB_CDROM is specified.
- */
-static char *cdrom_rootdevnames[] = {
-       "cd9660:cd0",
-       "cd9660:acd0",
-       NULL
-};
+static int
+mount_init(void *mem, int size, int flags)
+{
+       struct mount *mp;
 
-/* legacy find-root code */
-char           *rootdevnames[2] = {NULL, NULL};
-#ifndef ROOTDEVNAME
-#  define ROOTDEVNAME NULL
-#endif
-static const char      *ctrootdevname = ROOTDEVNAME;
+       mp = (struct mount *)mem;
+       mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF);
+       lockinit(&mp->mnt_explock, PVFS, "explock", 0, 0);
+       return (0);
+}
+
+static void
+mount_fini(void *mem, int size)
+{
+       struct mount *mp;
+
+       mp = (struct mount *)mem;
+       lockdestroy(&mp->mnt_explock);
+       mtx_destroy(&mp->mnt_mtx);
+}
+
+static void
+vfs_mount_init(void *dummy __unused)
+{
+
+       mount_zone = uma_zcreate("Mountpoints", sizeof(struct mount), NULL,
+           NULL, mount_init, mount_fini, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+}
+SYSINIT(vfs_mount, SI_SUB_VFS, SI_ORDER_ANY, vfs_mount_init, NULL);
 
 /*
  * ---------------------------------------------------------------------
@@ -452,27 +435,6 @@ vfs_rel(struct mount *mp)
        MNT_IUNLOCK(mp);
 }
 
-static int
-mount_init(void *mem, int size, int flags)
-{
-       struct mount *mp;
-
-       mp = (struct mount *)mem;
-       mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF);
-       lockinit(&mp->mnt_explock, PVFS, "explock", 0, 0);
-       return (0);
-}
-
-static void
-mount_fini(void *mem, int size)
-{
-       struct mount *mp;
-
-       mp = (struct mount *)mem;
-       lockdestroy(&mp->mnt_explock);
-       mtx_destroy(&mp->mnt_mtx);
-}
-
 /*
  * Allocate and initialize the mount point struct.
  */
@@ -1384,281 +1346,6 @@ dounmount(mp, flags, td)
 }
 
 /*
- * ---------------------------------------------------------------------
- * Mounting of root filesystem
- *
- */
-
-struct root_hold_token {
-       const char                      *who;
-       LIST_ENTRY(root_hold_token)     list;
-};
-
-static LIST_HEAD(, root_hold_token)    root_holds =
-    LIST_HEAD_INITIALIZER(root_holds);
-
-static int root_mount_complete;
-
-/*
- * Hold root mount.
- */
-struct root_hold_token *
-root_mount_hold(const char *identifier)
-{
-       struct root_hold_token *h;
-
-       if (root_mounted())
-               return (NULL);
-
-       h = malloc(sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK);
-       h->who = identifier;
-       mtx_lock(&mountlist_mtx);
-       LIST_INSERT_HEAD(&root_holds, h, list);
-       mtx_unlock(&mountlist_mtx);
-       return (h);
-}
-
-/*
- * Release root mount.
- */
-void
-root_mount_rel(struct root_hold_token *h)
-{
-
-       if (h == NULL)
-               return;
-       mtx_lock(&mountlist_mtx);
-       LIST_REMOVE(h, list);
-       wakeup(&root_holds);
-       mtx_unlock(&mountlist_mtx);
-       free(h, M_DEVBUF);
-}
-
-/*
- * Wait for all subsystems to release root mount.
- */
-static void
-root_mount_prepare(void)
-{
-       struct root_hold_token *h;
-       struct timeval lastfail;
-       int curfail = 0;
-
-       for (;;) {
-               DROP_GIANT();
-               g_waitidle();
-               PICKUP_GIANT();
-               mtx_lock(&mountlist_mtx);
-               if (LIST_EMPTY(&root_holds)) {
-                       mtx_unlock(&mountlist_mtx);
-                       break;
-               }
-               if (ppsratecheck(&lastfail, &curfail, 1)) {
-                       printf("Root mount waiting for:");
-                       LIST_FOREACH(h, &root_holds, list)
-                               printf(" %s", h->who);
-                       printf("\n");
-               }
-               msleep(&root_holds, &mountlist_mtx, PZERO | PDROP, "roothold",
-                   hz);
-       }
-}
-
-/*
- * Root was mounted, share the good news.
- */
-static void
-root_mount_done(void)
-{
-
-       /* Keep prison0's root in sync with the global rootvnode. */
-       mtx_lock(&prison0.pr_mtx);
-       prison0.pr_root = rootvnode;
-       vref(prison0.pr_root);
-       mtx_unlock(&prison0.pr_mtx);
-       /*
-        * Use a mutex to prevent the wakeup being missed and waiting for
-        * an extra 1 second sleep.
-        */
-       mtx_lock(&mountlist_mtx);
-       root_mount_complete = 1;
-       wakeup(&root_mount_complete);
-       mtx_unlock(&mountlist_mtx);
-}
-
-/*
- * Return true if root is already mounted.
- */
-int
-root_mounted(void)
-{
-
-       /* No mutex is acquired here because int stores are atomic. */
-       return (root_mount_complete);
-}
-
-/*
- * Wait until root is mounted.
- */
-void
-root_mount_wait(void)
-{
-
-       /*
-        * Panic on an obvious deadlock - the function can't be called from
-        * a thread which is doing the whole SYSINIT stuff.
-        */
-       KASSERT(curthread->td_proc->p_pid != 0,
-           ("root_mount_wait: cannot be called from the swapper thread"));
-       mtx_lock(&mountlist_mtx);
-       while (!root_mount_complete) {
-               msleep(&root_mount_complete, &mountlist_mtx, PZERO, "rootwait",
-                   hz);
-       }
-       mtx_unlock(&mountlist_mtx);
-}
-
-static void
-set_rootvnode()
-{
-       struct proc *p;
-
-       if (VFS_ROOT(TAILQ_FIRST(&mountlist), LK_EXCLUSIVE, &rootvnode))
-               panic("Cannot find root vnode");
-
-       VOP_UNLOCK(rootvnode, 0);
-
-       p = curthread->td_proc;
-       FILEDESC_XLOCK(p->p_fd);
-
-       if (p->p_fd->fd_cdir != NULL)
-               vrele(p->p_fd->fd_cdir);
-       p->p_fd->fd_cdir = rootvnode;
-       VREF(rootvnode);
-
-       if (p->p_fd->fd_rdir != NULL)
-               vrele(p->p_fd->fd_rdir);
-       p->p_fd->fd_rdir = rootvnode;
-       VREF(rootvnode);
-
-       FILEDESC_XUNLOCK(p->p_fd);
-
-       EVENTHANDLER_INVOKE(mountroot);
-}
-
-/*
- * Mount /devfs as our root filesystem, but do not put it on the mountlist
- * yet.  Create a /dev -> / symlink so that absolute pathnames will lookup.
- */
-
-static void
-devfs_first(void)
-{
-       struct thread *td = curthread;
-       struct vfsoptlist *opts;
-       struct vfsconf *vfsp;
-       struct mount *mp = NULL;
-       int error;
-
-       vfsp = vfs_byname("devfs");
-       KASSERT(vfsp != NULL, ("Could not find devfs by name"));
-       if (vfsp == NULL)
-               return;
-
-       mp = vfs_mount_alloc(NULLVP, vfsp, "/dev", td->td_ucred);
-
-       error = VFS_MOUNT(mp);
-       KASSERT(error == 0, ("VFS_MOUNT(devfs) failed %d", error));
-       if (error)
-               return;
-
-       opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK);
-       TAILQ_INIT(opts);
-       mp->mnt_opt = opts;
-
-       mtx_lock(&mountlist_mtx);
-       TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
-       mtx_unlock(&mountlist_mtx);
-
-       set_rootvnode();
-
-       error = kern_symlink(td, "/", "dev", UIO_SYSSPACE);
-       if (error)
-               printf("kern_symlink /dev -> / returns %d\n", error);
-}
-
-/*
- * Surgically move our devfs to be mounted on /dev.
- */
-
-static void
-devfs_fixup(struct thread *td)
-{
-       struct nameidata nd;
-       struct vnode *vp, *dvp;
-       struct mount *mp;
-       int error;
-
-       /* Remove our devfs mount from the mountlist and purge the cache */
-       mtx_lock(&mountlist_mtx);
-       mp = TAILQ_FIRST(&mountlist);
-       TAILQ_REMOVE(&mountlist, mp, mnt_list);
-       mtx_unlock(&mountlist_mtx);
-       cache_purgevfs(mp);
-
-       VFS_ROOT(mp, LK_EXCLUSIVE, &dvp);
-       VI_LOCK(dvp);
-       dvp->v_iflag &= ~VI_MOUNT;
-       VI_UNLOCK(dvp);
-       dvp->v_mountedhere = NULL;
-
-       /* Set up the real rootvnode, and purge the cache */
-       TAILQ_FIRST(&mountlist)->mnt_vnodecovered = NULL;
-       set_rootvnode();
-       cache_purgevfs(rootvnode->v_mount);
-
-       NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, "/dev", td);
-       error = namei(&nd);
-       if (error) {
-               printf("Lookup of /dev for devfs, error: %d\n", error);
-               vput(dvp);
-               vfs_unbusy(mp);
-               return;
-       }
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       vp = nd.ni_vp;
-       if (vp->v_type != VDIR) {
-               printf("/dev is not a directory\n");
-               vput(dvp);
-               vput(vp);
-               vfs_unbusy(mp);
-               return;
-       }
-       error = vinvalbuf(vp, V_SAVE, 0, 0);
-       if (error) {
-               printf("vinvalbuf() of /dev failed, error: %d\n", error);
-               vput(dvp);
-               vput(vp);
-               vfs_unbusy(mp);
-               return;
-       }
-       cache_purge(vp);
-       mp->mnt_vnodecovered = vp;
-       vp->v_mountedhere = mp;
-       mtx_lock(&mountlist_mtx);
-       TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
-       mtx_unlock(&mountlist_mtx);
-       VOP_UNLOCK(vp, 0);
-       vput(dvp);
-       vfs_unbusy(mp);
-
-       /* Unlink the no longer needed /dev/dev -> / symlink */
-       error = kern_unlink(td, "/dev/dev", UIO_SYSSPACE);
-       if (error)
-               printf("kern_unlink of /dev/dev failed, error: %d\n", error);
-}
-
-/*
  * Report errors during filesystem mounting.
  */
 void
@@ -1695,288 +1382,6 @@ vfs_opterror(struct vfsoptlist *opts, co
 }
 
 /*
- * Find and mount the root filesystem
- */
-void
-vfs_mountroot(void)
-{
-       char *cp, *cpt, *options, *tmpdev;
-       int error, i, asked = 0;
-
-       options = NULL;
-
-       root_mount_prepare();
-
-       mount_zone = uma_zcreate("Mountpoints", sizeof(struct mount),
-           NULL, NULL, mount_init, mount_fini,
-           UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
-       devfs_first();
-
-       /*
-        * We are booted with instructions to prompt for the root filesystem.
-        */
-       if (boothowto & RB_ASKNAME) {
-               if (!vfs_mountroot_ask())
-                       goto mounted;
-               asked = 1;
-       }
-
-       options = getenv("vfs.root.mountfrom.options");
-
-       /*
-        * The root filesystem information is compiled in, and we are
-        * booted with instructions to use it.
-        */
-       if (ctrootdevname != NULL && (boothowto & RB_DFLTROOT)) {
-               if (!vfs_mountroot_try(ctrootdevname, options))
-                       goto mounted;
-               ctrootdevname = NULL;
-       }
-
-       /*
-        * We've been given the generic "use CDROM as root" flag.  This is
-        * necessary because one media may be used in many different
-        * devices, so we need to search for them.
-        */
-       if (boothowto & RB_CDROM) {
-               for (i = 0; cdrom_rootdevnames[i] != NULL; i++) {
-                       if (!vfs_mountroot_try(cdrom_rootdevnames[i], options))
-                               goto mounted;
-               }
-       }
-
-       /*
-        * Try to use the value read by the loader from /etc/fstab, or
-        * supplied via some other means.  This is the preferred
-        * mechanism.
-        */
-       cp = getenv("vfs.root.mountfrom");
-       if (cp != NULL) {
-               cpt = cp;
-               while ((tmpdev = strsep(&cpt, " \t")) != NULL) {
-                       error = vfs_mountroot_try(tmpdev, options);
-                       if (error == 0) {
-                               freeenv(cp);
-                               goto mounted;
-                       }
-               }
-               freeenv(cp);
-       }
-
-       /*
-        * Try values that may have been computed by code during boot
-        */
-       if (!vfs_mountroot_try(rootdevnames[0], options))
-               goto mounted;
-       if (!vfs_mountroot_try(rootdevnames[1], options))
-               goto mounted;
-
-       /*
-        * If we (still) have a compiled-in default, try it.
-        */
-       if (ctrootdevname != NULL)
-               if (!vfs_mountroot_try(ctrootdevname, options))
-                       goto mounted;
-       /*
-        * Everything so far has failed, prompt on the console if we haven't
-        * already tried that.
-        */
-       if (!asked)
-               if (!vfs_mountroot_ask())
-                       goto mounted;
-
-       panic("Root mount failed, startup aborted.");
-
-mounted:
-       root_mount_done();
-       freeenv(options);
-}
-
-static struct mntarg *
-parse_mountroot_options(struct mntarg *ma, const char *options)
-{
-       char *p;
-       char *name, *name_arg;
-       char *val, *val_arg;
-       char *opts;
-
-       if (options == NULL || options[0] == '\0')
-               return (ma);
-
-       p = opts = strdup(options, M_MOUNT);
-       if (opts == NULL) {
-               return (ma);
-       } 
-
-       while((name = strsep(&p, ",")) != NULL) {
-               if (name[0] == '\0')
-                       break;
-
-               val = strchr(name, '=');
-               if (val != NULL) {
-                       *val = '\0';
-                       ++val;
-               }
-               if( strcmp(name, "rw") == 0 ||
-                   strcmp(name, "noro") == 0) {
-                       /*
-                        * The first time we mount the root file system,
-                        * we need to mount 'ro', so We need to ignore
-                        * 'rw' and 'noro' mount options.
-                        */
-                       continue;
-               }
-               name_arg = strdup(name, M_MOUNT);
-               val_arg = NULL;
-               if (val != NULL) 
-                       val_arg = strdup(val, M_MOUNT);
-
-               ma = mount_arg(ma, name_arg, val_arg,
-                   (val_arg != NULL ? -1 : 0));
-       }
-       free(opts, M_MOUNT);
-       return (ma);
-}
-
-/*
- * Mount (mountfrom) as the root filesystem.
- */
-static int
-vfs_mountroot_try(const char *mountfrom, const char *options)
-{
-       struct mount    *mp;
-       struct mntarg   *ma;
-       char            *vfsname, *path;
-       time_t          timebase;
-       int             error;
-       char            patt[32];
-       char            errmsg[255];
-
-       vfsname = NULL;
-       path    = NULL;
-       mp      = NULL;
-       ma      = NULL;
-       error   = EINVAL;
-       bzero(errmsg, sizeof(errmsg));
-
-       if (mountfrom == NULL)
-               return (error);         /* don't complain */
-       printf("Trying to mount root from %s\n", mountfrom);
-
-       /* parse vfs name and path */
-       vfsname = malloc(MFSNAMELEN, M_MOUNT, M_WAITOK);
-       path = malloc(MNAMELEN, M_MOUNT, M_WAITOK);
-       vfsname[0] = path[0] = 0;
-       sprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN);
-       if (sscanf(mountfrom, patt, vfsname, path) < 1)
-               goto out;
-
-       if (path[0] == '\0')
-               strcpy(path, ROOTNAME);
-
-       ma = mount_arg(ma, "fstype", vfsname, -1);
-       ma = mount_arg(ma, "fspath", "/", -1);
-       ma = mount_arg(ma, "from", path, -1);
-       ma = mount_arg(ma, "errmsg", errmsg, sizeof(errmsg));
-       ma = mount_arg(ma, "ro", NULL, 0);
-       ma = parse_mountroot_options(ma, options);
-       error = kernel_mount(ma, MNT_ROOTFS);
-
-       if (error == 0) {
-               /*
-                * We mount devfs prior to mounting the / FS, so the first
-                * entry will typically be devfs.
-                */
-               mp = TAILQ_FIRST(&mountlist);
-               KASSERT(mp != NULL, ("%s: mountlist is empty", __func__));
-
-               /*
-                * Iterate over all currently mounted file systems and use
-                * the time stamp found to check and/or initialize the RTC.
-                * Typically devfs has no time stamp and the only other FS
-                * is the actual / FS.
-                * Call inittodr() only once and pass it the largest of the
-                * timestamps we encounter.
-                */
-               timebase = 0;
-               do {
-                       if (mp->mnt_time > timebase)
-                               timebase = mp->mnt_time;
-                       mp = TAILQ_NEXT(mp, mnt_list);
-               } while (mp != NULL);
-               inittodr(timebase);
-
-               devfs_fixup(curthread);
-       }
-
-       if (error != 0 ) {
-               printf("ROOT MOUNT ERROR: %s\n", errmsg);
-               printf("If you have invalid mount options, reboot, and ");
-               printf("first try the following from\n");
-               printf("the loader prompt:\n\n");
-               printf("     set vfs.root.mountfrom.options=rw\n\n");
-               printf("and then remove invalid mount options from ");
-               printf("/etc/fstab.\n\n");
-       }
-out:
-       free(path, M_MOUNT);
-       free(vfsname, M_MOUNT);
-       return (error);
-}
-
-/*
- * ---------------------------------------------------------------------
- * Interactive root filesystem selection code.
- */
-
-static int
-vfs_mountroot_ask(void)
-{
-       char name[128];
-       char *mountfrom;
-       char *options;
-
-       for(;;) {
-               printf("Loader variables:\n");
-               printf("vfs.root.mountfrom=");
-               mountfrom = getenv("vfs.root.mountfrom");
-               if (mountfrom != NULL) {
-                       printf("%s", mountfrom);
-               }
-               printf("\n");
-               printf("vfs.root.mountfrom.options=");
-               options = getenv("vfs.root.mountfrom.options");
-               if (options != NULL) {
-                       printf("%s", options);
-               }
-               printf("\n");
-               freeenv(mountfrom);
-               freeenv(options);
-               printf("\nManual root filesystem specification:\n");
-               printf("  <fstype>:<device>  Mount <device> using filesystem 
<fstype>\n");
-               printf("                       eg. zfs:tank\n");
-               printf("                       eg. ufs:/dev/da0s1a\n");
-               printf("                       eg. cd9660:/dev/acd0\n");
-               printf("                       This is equivalent to: ");
-               printf("mount -t cd9660 /dev/acd0 /\n"); 
-               printf("\n");
-               printf("  ?                  List valid disk boot devices\n");
-               printf("  <empty line>       Abort manual input\n");
-               printf("\nmountroot> ");
-               gets(name, sizeof(name), 1);
-               if (name[0] == '\0')
-                       return (1);
-               if (name[0] == '?') {
-                       printf("\nList of GEOM managed disk devices:\n  ");
-                       g_dev_print();
-                       continue;
-               }
-               if (!vfs_mountroot_try(name, NULL))
-                       return (0);
-       }
-}
-
-/*
  * ---------------------------------------------------------------------
  * Functions for querying mount options/arguments from filesystems.
  */

Added: head/sys/kern/vfs_mountroot.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/kern/vfs_mountroot.c       Sat Oct  2 19:44:13 2010        
(r213365)
@@ -0,0 +1,626 @@
+/*-
+ * Copyright (c) 1999-2004 Poul-Henning Kamp
+ * Copyright (c) 1999 Michael Smith
+ * Copyright (c) 1989, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/filedesc.h>
+#include <sys/reboot.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <vm/uma.h>
+
+#include <geom/geom.h>
+
+#include <machine/stdarg.h>
+
+#include "opt_rootdevname.h"
+
+#define        ROOTNAME                "root_device"
+
+static int     vfs_mountroot_ask(void);
+static int     vfs_mountroot_try(const char *mountfrom, const char *options);
+
+/*
+ * The vnode of the system's root (/ in the filesystem, without chroot
+ * active.)
+ */
+struct vnode   *rootvnode;
+
+/*
+ * The root filesystem is detailed in the kernel environment variable
+ * vfs.root.mountfrom, which is expected to be in the general format
+ *
+ * <vfsname>:[<path>][ <vfsname>:[<path>] ...]
+ * vfsname   := the name of a VFS known to the kernel and capable
+ *              of being mounted as root
+ * path      := disk device name or other data used by the filesystem
+ *              to locate its physical store
+ *
+ * If the environment variable vfs.root.mountfrom is a space separated list,
+ * each list element is tried in turn and the root filesystem will be mounted
+ * from the first one that suceeds.
+ *
+ * The environment variable vfs.root.mountfrom.options is a comma delimited
+ * set of string mount options.  These mount options must be parseable
+ * by nmount() in the kernel.
+ */
+
+/*
+ * The root specifiers we will try if RB_CDROM is specified.
+ */
+static char *cdrom_rootdevnames[] = {
+       "cd9660:cd0",
+       "cd9660:acd0",
+       NULL
+};
+
+/* legacy find-root code */
+char           *rootdevnames[2] = {NULL, NULL};
+#ifndef ROOTDEVNAME
+#  define ROOTDEVNAME NULL
+#endif
+static const char      *ctrootdevname = ROOTDEVNAME;
+
+struct root_hold_token {
+       const char                      *who;
+       LIST_ENTRY(root_hold_token)     list;
+};
+
+static LIST_HEAD(, root_hold_token)    root_holds =
+    LIST_HEAD_INITIALIZER(root_holds);
+
+static int root_mount_complete;
+
+struct root_hold_token *
+root_mount_hold(const char *identifier)
+{
+       struct root_hold_token *h;
+
+       if (root_mounted())
+               return (NULL);
+
+       h = malloc(sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK);
+       h->who = identifier;
+       mtx_lock(&mountlist_mtx);
+       LIST_INSERT_HEAD(&root_holds, h, list);
+       mtx_unlock(&mountlist_mtx);
+       return (h);
+}
+
+void
+root_mount_rel(struct root_hold_token *h)
+{
+
+       if (h == NULL)
+               return;
+       mtx_lock(&mountlist_mtx);
+       LIST_REMOVE(h, list);
+       wakeup(&root_holds);
+       mtx_unlock(&mountlist_mtx);
+       free(h, M_DEVBUF);
+}
+
+static void
+root_mount_prepare(void)
+{
+       struct root_hold_token *h;
+       struct timeval lastfail;
+       int curfail = 0;
+
+       for (;;) {
+               DROP_GIANT();
+               g_waitidle();
+               PICKUP_GIANT();
+               mtx_lock(&mountlist_mtx);
+               if (LIST_EMPTY(&root_holds)) {
+                       mtx_unlock(&mountlist_mtx);
+                       break;
+               }
+               if (ppsratecheck(&lastfail, &curfail, 1)) {
+                       printf("Root mount waiting for:");
+                       LIST_FOREACH(h, &root_holds, list)
+                               printf(" %s", h->who);
+                       printf("\n");
+               }
+               msleep(&root_holds, &mountlist_mtx, PZERO | PDROP, "roothold",
+                   hz);
+       }
+}
+
+static void
+root_mount_done(void)
+{
+
+       /* Keep prison0's root in sync with the global rootvnode. */
+       mtx_lock(&prison0.pr_mtx);
+       prison0.pr_root = rootvnode;
+       vref(prison0.pr_root);
+       mtx_unlock(&prison0.pr_mtx);
+       /*
+        * Use a mutex to prevent the wakeup being missed and waiting for
+        * an extra 1 second sleep.
+        */
+       mtx_lock(&mountlist_mtx);
+       root_mount_complete = 1;
+       wakeup(&root_mount_complete);
+       mtx_unlock(&mountlist_mtx);
+}
+
+int
+root_mounted(void)
+{
+
+       /* No mutex is acquired here because int stores are atomic. */
+       return (root_mount_complete);
+}
+
+void
+root_mount_wait(void)
+{
+
+       /*
+        * Panic on an obvious deadlock - the function can't be called from
+        * a thread which is doing the whole SYSINIT stuff.
+        */
+       KASSERT(curthread->td_proc->p_pid != 0,
+           ("root_mount_wait: cannot be called from the swapper thread"));
+       mtx_lock(&mountlist_mtx);
+       while (!root_mount_complete) {
+               msleep(&root_mount_complete, &mountlist_mtx, PZERO, "rootwait",
+                   hz);
+       }
+       mtx_unlock(&mountlist_mtx);
+}
+
+static void
+set_rootvnode(void)
+{
+       struct proc *p;
+
+       if (VFS_ROOT(TAILQ_FIRST(&mountlist), LK_EXCLUSIVE, &rootvnode))
+               panic("Cannot find root vnode");
+
+       VOP_UNLOCK(rootvnode, 0);
+
+       p = curthread->td_proc;
+       FILEDESC_XLOCK(p->p_fd);
+
+       if (p->p_fd->fd_cdir != NULL)
+               vrele(p->p_fd->fd_cdir);
+       p->p_fd->fd_cdir = rootvnode;
+       VREF(rootvnode);
+
+       if (p->p_fd->fd_rdir != NULL)
+               vrele(p->p_fd->fd_rdir);
+       p->p_fd->fd_rdir = rootvnode;
+       VREF(rootvnode);
+
+       FILEDESC_XUNLOCK(p->p_fd);
+
+       EVENTHANDLER_INVOKE(mountroot);
+}
+
+static void
+devfs_first(void)
+{
+       struct thread *td = curthread;
+       struct vfsoptlist *opts;
+       struct vfsconf *vfsp;
+       struct mount *mp = NULL;
+       int error;
+
+       vfsp = vfs_byname("devfs");
+       KASSERT(vfsp != NULL, ("Could not find devfs by name"));
+       if (vfsp == NULL)
+               return;
+
+       mp = vfs_mount_alloc(NULLVP, vfsp, "/dev", td->td_ucred);
+
+       error = VFS_MOUNT(mp);
+       KASSERT(error == 0, ("VFS_MOUNT(devfs) failed %d", error));
+       if (error)
+               return;
+
+       opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK);
+       TAILQ_INIT(opts);
+       mp->mnt_opt = opts;
+
+       mtx_lock(&mountlist_mtx);
+       TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
+       mtx_unlock(&mountlist_mtx);
+
+       set_rootvnode();
+
+       error = kern_symlink(td, "/", "dev", UIO_SYSSPACE);
+       if (error)
+               printf("kern_symlink /dev -> / returns %d\n", error);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to