vfs_synth - rewrite
authorAlex Hornung <ahornung@gmail.com>
Sun, 14 Mar 2010 08:57:36 +0000 (14 08:57 +0000)
committerAlex Hornung <ahornung@gmail.com>
Sun, 14 Mar 2010 12:37:31 +0000 (14 12:37 +0000)
* Rewrite the whole vfs_synth mess to be compatible with devfs. Now we
  create a synthetic mountpoint and mount devfs on it. We then just
  nlookup() whatever device we need on that mountpoint.

* This also fixes vinum rootmount. To use vinum as a root,
  vfs.root.mountfrom in /boot/loader.conf has to be set to
  "<fs>:vinum/vinumroot" where <fs> can be ufs or hammer.

Reported-by: Rumko, tuxillo
Dragonfly-bug: http://bugs.dragonflybsd.org/issue1565

sys/kern/vfs_synth.c

index 64173f7..3bc1eb4 100644 (file)
@@ -1,13 +1,13 @@
 /*
- * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
- * 
+ * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
+ *
  * This code is derived from software contributed to The DragonFly Project
- * by Matthew Dillon <dillon@backplane.com>
- * 
+ * by Alex Hornung <ahornung (at) gmail.com>
+ *
  * 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
@@ -17,7 +17,7 @@
  * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  * 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.
- * 
- * $DragonFly: src/sys/kern/vfs_synth.c,v 1.1 2007/07/30 08:02:38 dillon Exp $
- */
-
-/*
- * Synthesize vnodes for devices.  Devices have certain requirements and
- * limitations with regards to opening and closing, and physical I/O
- * limits.  This module allows you to synthesize a specfs-backed vnode
- * for a device.
  */
 
 #include <sys/param.h>
 #include <sys/lock.h>
 #include <sys/disk.h>
 #include <sys/mount.h>
-
+#include <sys/namecache.h>
+#include <sys/nlookup.h>
+#include <sys/proc.h>
 #include <sys/thread2.h>
+#include <sys/devfs.h>
 
-static struct mount *synth_mount;
+struct mount   *synth_mp;
+struct vnode   *synth_vp;
+static int     synth_inited = 0;
+static int     synth_synced = 0;
 
-/*
- * getsynthvnode() - return a vnode representing a device.
- *
- * The caller must VOP_OPEN() the vnode as appropriate before using it for
- * I/O, and VOP_CLOSE() it when finished.
- *
- * The returned vnode will be referenced and locked.  The caller must
- * vrele() the vnode when finished with it.
- */
 struct vnode *
 getsynthvnode(const char *devname)
 {
        struct vnode *vp;
+       struct nchandle nch;
+       struct nlookupdata nd;
+       struct ucred *cred = proc0.p_ucred;
        int error;
-       cdev_t dev;
-
-       dev = disk_locate(devname);
-       if (dev == NULL)
-               return(NULL);
-
-       error = getnewvnode(VT_SYNTH, synth_mount, &vp, 0, 0);
-       if (error)
-               panic("getsynthvnode: unable to get new vnode");
-       vp->v_type = VCHR;
-       addaliasu(vp, dev->si_umajor, dev->si_uminor);
-       return(vp);
-}
-
-/*
- * VOP support - use specfs and dummy up the mount.
- */
-
-static int synth_inactive(struct vop_inactive_args *ap);
-static int synth_reclaim(struct vop_reclaim_args *ap);
-
-struct vop_ops synth_vnode_vops = {
-       .vop_default            = vop_defaultop,
-       .vop_inactive           = synth_inactive,
-       .vop_reclaim            = synth_reclaim
-};
-
-VNODEOP_SET(synth_vnode_vops);
 
-static
-int
-synth_inactive(struct vop_inactive_args *ap)
-{
-       vrecycle(ap->a_vp);
-       return (0);
-}
-
-static
-int
-synth_reclaim(struct vop_reclaim_args *ap)
-{
-       ap->a_vp->v_data = NULL;
-       return(0);
-}
-
-/*
- * Create a dummy mount structure and VFS.  This VFS is not currently
- * mountable.
- */
-static int synth_vfs_mount(struct mount *, char *, caddr_t, struct ucred *);
-static int synth_vfs_unmount(struct mount *, int mntflags);
-static int synth_vfs_root(struct mount *mp, struct vnode **vpp);
-
-static struct vfsops synth_vfsops = {
-       .vfs_mount      = synth_vfs_mount,
-       .vfs_root       = synth_vfs_root,
-       .vfs_unmount    = synth_vfs_unmount
-};
-
-static struct vfsconf synth_vfsconf = {
-       .vfc_vfsops = &synth_vfsops,
-       .vfc_name = { "synth" },
-       .vfc_typenum = VT_SYNTH
-};
-
-static
-int
-synth_vfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
-{
-       return (EINVAL);
+       KKASSERT(synth_inited != 0);
+       KKASSERT(synth_mp != NULL);
+       KKASSERT(synth_mp->mnt_ncmountpt.mount != NULL);
+
+       /* Sync devfs/disks twice to make sure all devices are around */
+       if (synth_synced < 2) {
+               sync_devs();
+               ++synth_synced;
+       }
+
+       error = nlookup_init_root(&nd,
+            devname, UIO_SYSSPACE, NLC_FOLLOW,
+            cred, &synth_mp->mnt_ncmountpt,
+            &synth_mp->mnt_ncmountpt);
+
+       if (error) {
+               panic("synth: nlookup_init_root failed with %d\n", error);
+               /* NOTREACHED */
+       }
+
+       error = nlookup(&nd);
+       if (error == 0) {
+               if (nd.nl_nch.ncp->nc_vp == NULL) {
+                       kprintf("synth: nc_vp == NULL\n");
+                       return (NULL);
+               }
+               nch = nd.nl_nch;
+               cache_zero(&nd.nl_nch);
+       }
+
+       nlookup_done(&nd);
+       if (error) {
+               if (error != ENOENT) { /* Don't bother warning about ENOENT */
+                       kprintf("synth: nlookup of %s failed with %d\n",
+                           devname, error);
+               }
+               return (NULL);
+       }
+
+       vp = nch.ncp->nc_vp;
+       /* A VX locked & refd vnode must be returned. */
+       error = vget(vp, LK_EXCLUSIVE);
+       cache_unlock(&nch);
+
+       if (error) {
+               kprintf("synth: could not vget vnode\n");
+               return (NULL);
+       }
+
+       return (vp);
 }
 
-static
-int
-synth_vfs_unmount(struct mount *mp, int mntflags)
-{
-       return (0);
-}
-
-static
-int
-synth_vfs_root(struct mount *mp, struct vnode **vpp)
-{
-       *vpp = NULL;
-       return (EINVAL);
-}
-
-/*
- * We have to register our VFS and create our dummy mount structure before
- * devices configure or vinum will not be able to configure at boot.  The
- * standard usage via VFS_SET() is registered too late.
- */
-static
-void
+static void
 synthinit(void *arg __unused)
 {
        int error;
 
-       error = vfs_register(&synth_vfsconf);
-       KKASSERT(error == 0);
-       error = vfs_rootmountalloc("synth", "dummy", &synth_mount);
-       KKASSERT(error == 0);
-       synth_mount->mnt_vn_use_ops = &synth_vnode_vops;
+       if ((error = vfs_rootmountalloc("devfs", "dummy", &synth_mp))) {
+               panic("synth: vfs_rootmountalloc failed with %d\n", error);
+               /* NOTREACHED */
+       }
+       if ((error = VFS_MOUNT(synth_mp, NULL, NULL, proc0.p_ucred))) {
+               panic("synth: vfs_mount failed with %d\n", error);
+               /* NOTREACHED */
+       }
+       if ((error = VFS_ROOT(synth_mp, &synth_vp))) {
+               panic("synth: vfs_root failed with %d\n", error);
+               /* NOTREACHED */
+       }
+       cache_allocroot(&synth_mp->mnt_ncmountpt, synth_mp, synth_vp);
+       cache_unlock(&synth_mp->mnt_ncmountpt); /* leave ref intact */
+       vput(synth_vp);
+
+       synth_inited = 1;
 }
 
-SYSINIT(synthinit, SI_SUB_CREATE_INIT, SI_ORDER_ANY, synthinit, NULL)
-
+SYSINIT(synthinit, SI_SUB_VFS, SI_ORDER_ANY, synthinit, NULL)