VFS messaging/interfacing work stage 4/99. This stage goes a long ways
authorMatthew Dillon <dillon@dragonflybsd.org>
Sat, 28 Aug 2004 19:02:35 +0000 (19:02 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sat, 28 Aug 2004 19:02:35 +0000 (19:02 +0000)
towards allowing us to move the vnode locking into a kernel layer.  It
gets rid of a lot of cruft from FreeBSD-4.  FreeBSD-5 has done some of this
stuff too (such as changing the default locking to stdlock from nolock),
but DragonFly is going further.

* Consolidate vnode locks into the vnode structure, add an embedded v_lock,
  and getting rid of both v_vnlock and v_data based head-of-structure locks.

* Change the default vops to use a standard vnode lock rather then a fake
  non-lock.

* Get rid of vop_nolock() and friends, we no longer support non-locking
  vnodes.

* Get rid of vop_sharedlock(), we no longer support non standard shared-only
  locks (only NFS was using it and the mount-crossing lookup code should
  now prevent races to root from dead NFS volumes).

* Integrate lock initialization into getnewvnode().  We do not yet
  incorporate automatically locking into getnewvnode().  getnewvnode()
  now has two additional arguments, lktimeout and lkflags, for lock
  structure initialization.

* Change the sync vnode lock from nolock to stdlock.  This may require more
  tuning down the line.  Fix various sync_inactive() to properly unlock
  the lock as per the VOP API.

* Properly flag the 'rename' vop operation regarding required tdvp and tvp
  unlocks (the flags are only used by nullfs).

* Get rid of all inode-embedded vnode locks

* Remove manual lockinit and use new getnewvnode() args instead.
  Lock the vnode prior to doing anything that might block in
  order to avoid synclist access before the vnode has been properly
  initialize.

* Generally change inode hash insertion to also check
  for a hash collision and return failure if it occurs,
  rather then doing (often non-atomic) relookups and
  other checks.  These sorts of collisions can occur
  if a vnode is being destroyed at the same time a new
  vnode is being created from an inode.  A new vnode is
  not generally accessible, except by the sync code (from
  the mountlist) until it's underlying inode has been hashed
  so dealing with a hash collision should be as simple as
  throwing away the vnode with a vput().

* Do not initialize a new vnode's v_data until after
  the associated inode has been successfully added to
  the hash, and make the xxx_inactive() and xxx_reclaim()
  code friendly towards vnodes with a NULL v_data.

* NFS now uses standard locks rather then shared-only locks.

* PROCFS now uses standard locks rather then non-locks, and PROCFS's
  lookup code now understands VOP lookup semantics.  PROCFS now uses
  a real hash table for its node search rather then a single singly-linked
  list (which should better scale to systems with thousands of processes).

* NULLFS should now properly handle lookup() and rename() locks.  NULLFS's
  node handling code has been rewritten.  NULLFS's bypass code now understands
  vnode unlocks (rename case).

* UFS no longer needs the ffs_inode_hash_lock hacks.  It now uses the new
  collision-on-hash-add methodology.   This will speed up UFS when operating
  on lots of small files (reported by David Rhodus).

51 files changed:
sys/emulation/linux/i386/linprocfs/linprocfs_subr.c
sys/kern/kern_lock.c
sys/kern/vfs_default.c
sys/kern/vfs_subr.c
sys/kern/vfs_vopops.c
sys/sys/lock.h
sys/sys/namecache.h
sys/sys/vnode.h
sys/vfs/coda/cnode.h
sys/vfs/coda/coda_vnops.c
sys/vfs/fdesc/fdesc_vnops.c
sys/vfs/gnu/ext2fs/ext2_vfsops.c
sys/vfs/hpfs/hpfs.h
sys/vfs/hpfs/hpfs_vfsops.c
sys/vfs/hpfs/hpfs_vnops.c
sys/vfs/isofs/cd9660/cd9660_node.c
sys/vfs/isofs/cd9660/cd9660_node.h
sys/vfs/isofs/cd9660/cd9660_vfsops.c
sys/vfs/mfs/mfs_vfsops.c
sys/vfs/msdosfs/denode.h
sys/vfs/msdosfs/msdosfs_denode.c
sys/vfs/msdosfs/msdosfs_vnops.c
sys/vfs/nfs/nfs_node.c
sys/vfs/nfs/nfs_vnops.c
sys/vfs/nfs/nfsnode.h
sys/vfs/ntfs/ntfs_inode.h
sys/vfs/ntfs/ntfs_vfsops.c
sys/vfs/nullfs/null.h
sys/vfs/nullfs/null_subr.c
sys/vfs/nullfs/null_vnops.c
sys/vfs/nwfs/nwfs_node.c
sys/vfs/portal/portal_vfsops.c
sys/vfs/portal/portal_vnops.c
sys/vfs/procfs/procfs_subr.c
sys/vfs/procfs/procfs_vfsops.c
sys/vfs/procfs/procfs_vnops.c
sys/vfs/smbfs/smbfs_node.c
sys/vfs/smbfs/smbfs_node.h
sys/vfs/smbfs/smbfs_vnops.c
sys/vfs/udf/udf_vnops.c
sys/vfs/ufs/ffs_vfsops.c
sys/vfs/ufs/inode.h
sys/vfs/ufs/ufs_extern.h
sys/vfs/ufs/ufs_ihash.c
sys/vfs/ufs/ufs_inode.c
sys/vfs/ufs/ufs_vnops.c
sys/vfs/umapfs/umap.h
sys/vfs/umapfs/umap_subr.c
sys/vfs/umapfs/umap_vnops.c
sys/vfs/union/union_subr.c
sys/vm/vm_swap.c

index 871c843..e1cb325 100644 (file)
@@ -39,7 +39,7 @@
  *     @(#)procfs_subr.c       8.6 (Berkeley) 5/14/95
  *
  * $FreeBSD: src/sys/i386/linux/linprocfs/linprocfs_subr.c,v 1.3.2.4 2001/06/25 19:46:47 pirzyk Exp $
- * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_subr.c,v 1.11 2004/08/17 18:57:32 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_subr.c,v 1.12 2004/08/28 19:02:04 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -125,7 +125,8 @@ loop:
         */
        MALLOC(pfs, struct pfsnode *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
 
-       if ((error = getnewvnode(VT_PROCFS, mp, mp->mnt_vn_ops, vpp)) != 0) {
+       error = getnewvnode(VT_PROCFS, mp, mp->mnt_vn_ops, vpp, 0, 0);
+       if (error) {
                FREE(pfs, M_TEMP);
                goto out;
        }
index 6ff5f13..63e81f3 100644 (file)
@@ -39,7 +39,7 @@
  *
  *     @(#)kern_lock.c 8.18 (Berkeley) 5/21/95
  * $FreeBSD: src/sys/kern/kern_lock.c,v 1.31.2.3 2001/12/25 01:44:44 dillon Exp $
- * $DragonFly: src/sys/kern/kern_lock.c,v 1.10 2004/03/01 06:33:17 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_lock.c,v 1.11 2004/08/28 19:02:05 dillon Exp $
  */
 
 #include "opt_lint.h"
@@ -473,12 +473,7 @@ acquiredrain(struct lock *lkp, int extflags)
  * Initialize a lock; required before use.
  */
 void
-lockinit(lkp, prio, wmesg, timo, flags)
-       struct lock *lkp;
-       int prio;
-       char *wmesg;
-       int timo;
-       int flags;
+lockinit(struct lock *lkp, int prio, char *wmesg, int timo, int flags)
 {
        lwkt_token_init(&lkp->lk_interlock);
        lkp->lk_flags = (flags & LK_EXTFLG_MASK);
@@ -491,6 +486,21 @@ lockinit(lkp, prio, wmesg, timo, flags)
        lkp->lk_lockholder = LK_NOTHREAD;
 }
 
+/*
+ * Reinitialize a lock that is being reused for a different purpose, but
+ * which may have pending (blocked) threads sitting on it.  The caller 
+ * must already hold the interlock.
+ */
+void
+lockreinit(struct lock *lkp, int prio, char *wmesg, int timo, int flags)
+{
+       lkp->lk_flags = (lkp->lk_flags & ~(LK_EXTFLG_MASK|LK_DRAINING)) |
+                       (flags & LK_EXTFLG_MASK);
+       lkp->lk_prio = prio;
+       lkp->lk_wmesg = wmesg;
+       lkp->lk_timo = timo;
+}
+
 /*
  * Determine the status of a lock.
  */
index a82d1b1..03fe3ab 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * $FreeBSD: src/sys/kern/vfs_default.c,v 1.28.2.7 2003/01/10 18:23:26 bde Exp $
- * $DragonFly: src/sys/kern/vfs_default.c,v 1.12 2004/08/17 18:57:32 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_default.c,v 1.13 2004/08/28 19:02:05 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -68,9 +68,7 @@ static int    vop_nostrategy (struct vop_strategy_args *);
  * implement a particular VOP.
  *
  * If there is no specific entry here, we will return EOPNOTSUPP.
- *
  */
-
 struct vop_ops *default_vnode_vops;
 static struct vnodeopv_entry_desc default_vnodeop_entries[] = {
        { &vop_default_desc,            vop_eopnotsupp },
@@ -82,9 +80,9 @@ static struct vnodeopv_entry_desc default_vnodeop_entries[] = {
        { &vop_fsync_desc,              vop_null },
        { &vop_getvobject_desc,         (void *) vop_stdgetvobject },
        { &vop_ioctl_desc,              vop_enotty },
-       { &vop_islocked_desc,           (void *) vop_noislocked },
+       { &vop_islocked_desc,           (void *) vop_stdislocked },
        { &vop_lease_desc,              vop_null },
-       { &vop_lock_desc,               (void *) vop_nolock },
+       { &vop_lock_desc,               (void *) vop_stdlock },
        { &vop_mmap_desc,               vop_einval },
        { &vop_lookup_desc,             (void *) vop_nolookup },
        { &vop_open_desc,               vop_null },
@@ -94,7 +92,7 @@ static struct vnodeopv_entry_desc default_vnodeop_entries[] = {
        { &vop_reallocblks_desc,        vop_eopnotsupp },
        { &vop_revoke_desc,             (void *) vop_stdrevoke },
        { &vop_strategy_desc,           (void *) vop_nostrategy },
-       { &vop_unlock_desc,             (void *) vop_nounlock },
+       { &vop_unlock_desc,             (void *) vop_stdunlock },
        { &vop_getacl_desc,             vop_eopnotsupp },
        { &vop_setacl_desc,             vop_eopnotsupp },
        { &vop_aclcheck_desc,           vop_eopnotsupp },
@@ -226,10 +224,8 @@ vop_stdpathconf(ap)
 }
 
 /*
- * Standard lock, unlock and islocked functions.
- *
- * These depend on the lock structure being the first element in the
- * inode, ie: vp->v_data points to the the lock!
+ * Standard lock.  The lock is recursive-capable only if the lock was
+ * initialized with LK_CANRECURSE or that flag is passed in a_flags.
  */
 int
 vop_stdlock(ap)
@@ -240,20 +236,17 @@ vop_stdlock(ap)
                struct proc *a_p;
        } */ *ap;
 {               
-       struct lock *l;
-
-       if ((l = (struct lock *)ap->a_vp->v_data) == NULL) {
-               if (ap->a_flags & LK_INTERLOCK)
-                       lwkt_reltoken(ap->a_vlock);
-               return 0;
-       }
+       int error;
 
 #ifndef        DEBUG_LOCKS
-       return (lockmgr(l, ap->a_flags, ap->a_vlock, ap->a_td));
+       error = lockmgr(&ap->a_vp->v_lock, ap->a_flags,
+                       ap->a_vlock, ap->a_td);
 #else
-       return (debuglockmgr(l, ap->a_flags, ap->a_vlock, ap->a_td,
-           "vop_stdlock", ap->a_vp->filename, ap->a_vp->line));
+       error = debuglockmgr(&ap->a_vp->v_lock, ap->a_flags,
+                       ap->a_vlock, ap->a_td,
+                       "vop_stdlock", ap->a_vp->filename, ap->a_vp->line);
 #endif
+       return(error);
 }
 
 int
@@ -265,15 +258,11 @@ vop_stdunlock(ap)
                struct thread *a_td;
        } */ *ap;
 {
-       struct lock *l;
+       int error;
 
-       if ((l = (struct lock *)ap->a_vp->v_data) == NULL) {
-               if (ap->a_flags & LK_INTERLOCK)
-                       lwkt_reltoken(ap->a_vlock);
-               return 0;
-       }
-
-       return (lockmgr(l, ap->a_flags | LK_RELEASE, ap->a_vlock, ap->a_td));
+       error = lockmgr(&ap->a_vp->v_lock, ap->a_flags | LK_RELEASE,
+                       ap->a_vlock, ap->a_td);
+       return(error);
 }
 
 int
@@ -283,12 +272,7 @@ vop_stdislocked(ap)
                struct thread *a_td;
        } */ *ap;
 {
-       struct lock *l;
-
-       if ((l = (struct lock *)ap->a_vp->v_data) == NULL)
-               return 0;
-
-       return (lockstatus(l, ap->a_td));
+       return (lockstatus(&ap->a_vp->v_lock, ap->a_td));
 }
 
 /*
@@ -340,171 +324,6 @@ vop_stdbwrite(ap)
        return (bwrite(ap->a_bp));
 }
 
-/*
- * Stubs to use when there is no locking to be done on the underlying object.
- * A minimal shared lock is necessary to ensure that the underlying object
- * is not revoked while an operation is in progress. So, an active shared
- * count is maintained in an auxillary vnode lock structure.
- */
-int
-vop_sharedlock(ap)
-       struct vop_lock_args /* {
-               struct vnode *a_vp;
-               lwkt_tokref_t a_vlock;
-               int a_flags;
-               struct proc *a_p;
-       } */ *ap;
-{
-       /*
-        * This code cannot be used until all the non-locking filesystems
-        * (notably NFS) are converted to properly lock and release nodes.
-        * Also, certain vnode operations change the locking state within
-        * the operation (create, mknod, remove, link, rename, mkdir, rmdir,
-        * and symlink). Ideally these operations should not change the
-        * lock state, but should be changed to let the caller of the
-        * function unlock them. Otherwise all intermediate vnode layers
-        * (such as union, umapfs, etc) must catch these functions to do
-        * the necessary locking at their layer. Note that the inactive
-        * and lookup operations also change their lock state, but this 
-        * cannot be avoided, so these two operations will always need
-        * to be handled in intermediate layers.
-        */
-       struct vnode *vp = ap->a_vp;
-       struct lock *l = (struct lock *)vp->v_data;
-       int vnflags, flags = ap->a_flags;
-
-       if (l == NULL) {
-               if (ap->a_flags & LK_INTERLOCK)
-                       lwkt_reltoken(ap->a_vlock);
-               return 0;
-       }
-       switch (flags & LK_TYPE_MASK) {
-       case LK_DRAIN:
-               vnflags = LK_DRAIN;
-               break;
-       case LK_EXCLUSIVE:
-#ifdef DEBUG_VFS_LOCKS
-               /*
-                * Normally, we use shared locks here, but that confuses
-                * the locking assertions.
-                */
-               vnflags = LK_EXCLUSIVE;
-               break;
-#endif
-       case LK_SHARED:
-               vnflags = LK_SHARED;
-               break;
-       case LK_UPGRADE:
-       case LK_EXCLUPGRADE:
-       case LK_DOWNGRADE:
-               return (0);
-       case LK_RELEASE:
-       default:
-               panic("vop_sharedlock: bad operation %d", flags & LK_TYPE_MASK);
-       }
-       if (flags & LK_INTERLOCK)
-               vnflags |= LK_INTERLOCK;
-#ifndef        DEBUG_LOCKS
-       return (lockmgr(l, vnflags, ap->a_vlock, ap->a_td));
-#else
-       return (debuglockmgr(l, vnflags, ap->a_vlock, ap->a_td,
-           "vop_sharedlock", vp->filename, vp->line));
-#endif
-}
-
-/*
- * Stubs to use when there is no locking to be done on the underlying object.
- * A minimal shared lock is necessary to ensure that the underlying object
- * is not revoked while an operation is in progress. So, an active shared
- * count is maintained in an auxillary vnode lock structure.
- */
-int
-vop_nolock(ap)
-       struct vop_lock_args /* {
-               struct vnode *a_vp;
-               lwkt_tokref_t a_vlock;
-               int a_flags;
-               struct proc *a_p;
-       } */ *ap;
-{
-#ifdef notyet
-       /*
-        * This code cannot be used until all the non-locking filesystems
-        * (notably NFS) are converted to properly lock and release nodes.
-        * Also, certain vnode operations change the locking state within
-        * the operation (create, mknod, remove, link, rename, mkdir, rmdir,
-        * and symlink). Ideally these operations should not change the
-        * lock state, but should be changed to let the caller of the
-        * function unlock them. Otherwise all intermediate vnode layers
-        * (such as union, umapfs, etc) must catch these functions to do
-        * the necessary locking at their layer. Note that the inactive
-        * and lookup operations also change their lock state, but this 
-        * cannot be avoided, so these two operations will always need
-        * to be handled in intermediate layers.
-        */
-       struct vnode *vp = ap->a_vp;
-       int vnflags, flags = ap->a_flags;
-
-       switch (flags & LK_TYPE_MASK) {
-       case LK_DRAIN:
-               vnflags = LK_DRAIN;
-               break;
-       case LK_EXCLUSIVE:
-       case LK_SHARED:
-               vnflags = LK_SHARED;
-               break;
-       case LK_UPGRADE:
-       case LK_EXCLUPGRADE:
-       case LK_DOWNGRADE:
-               return (0);
-       case LK_RELEASE:
-       default:
-               panic("vop_nolock: bad operation %d", flags & LK_TYPE_MASK);
-       }
-       if (flags & LK_INTERLOCK)
-               vnflags |= LK_INTERLOCK;
-       return(lockmgr(vp->v_vnlock, vnflags, ap->a_vlock, ap->a_p));
-#else /* for now */
-       /*
-        * Since we are not using the lock manager, we must clear
-        * the interlock here.
-        */
-       if (ap->a_flags & LK_INTERLOCK)
-               lwkt_reltoken(ap->a_vlock);
-       return (0);
-#endif
-}
-
-/*
- * Do the inverse of vop_nolock, handling the interlock in a compatible way.
- */
-int
-vop_nounlock(ap)
-       struct vop_unlock_args /* {
-               struct vnode *a_vp;
-               lwkt_tokref_t a_vlock;
-               int a_flags;
-               struct proc *a_p;
-       } */ *ap;
-{
-       if (ap->a_flags & LK_INTERLOCK)
-               lwkt_reltoken(ap->a_vlock);
-       return (0);
-}
-
-/*
- * Return whether or not the node is in use.
- */
-int
-vop_noislocked(ap)
-       struct vop_islocked_args /* {
-               struct vnode *a_vp;
-               struct proc *a_p;
-       } */ *ap;
-{
-       return (0);
-}
-
 int
 vop_stdcreatevobject(ap)
        struct vop_createvobject_args /* {
index 5904f33..e363b53 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_subr.c  8.31 (Berkeley) 5/26/95
  * $FreeBSD: src/sys/kern/vfs_subr.c,v 1.249.2.30 2003/04/04 20:35:57 tegge Exp $
- * $DragonFly: src/sys/kern/vfs_subr.c,v 1.37 2004/08/17 18:57:32 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_subr.c,v 1.38 2004/08/28 19:02:05 dillon Exp $
  */
 
 /*
@@ -624,8 +624,8 @@ SYSINIT(vnlru, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &vnlru_kp)
  * Return the next vnode from the free list.
  */
 int
-getnewvnode(enum vtagtype tag, struct mount *mp, 
-           struct vop_ops *ops, struct vnode **vpp)
+getnewvnode(enum vtagtype tag, struct mount *mp, struct vop_ops *ops,
+               struct vnode **vpp, int lktimeout, int lkflags)
 {
        int s;
        struct thread *td = curthread;  /* XXX */
@@ -786,12 +786,17 @@ getnewvnode(enum vtagtype tag, struct mount *mp,
                vp->v_clen = 0;
                vp->v_socket = 0;
                vp->v_writecount = 0;   /* XXX */
+               lockreinit(&vp->v_lock, 0, "vnode", lktimeout, lkflags);
        } else {
+               /*
+                * A brand-new vnode (we could use malloc() here I think) XXX
+                */
                lwkt_reltoken(&ilock);
                vp = zalloc(vnode_zone);
                bzero(vp, sizeof(*vp));
                vp->v_interlock = lwkt_token_pool_get(vp);
                lwkt_token_init(&vp->v_pollinfo.vpi_token);
+               lockinit(&vp->v_lock, 0, "vnode", lktimeout, lkflags);
                cache_purge(vp);
                TAILQ_INIT(&vp->v_namecache);
                numvnodes++;
@@ -1521,7 +1526,7 @@ bdevvp(dev_t dev, struct vnode **vpp)
                *vpp = NULLVP;
                return (ENXIO);
        }
-       error = getnewvnode(VT_NON, (struct mount *)0, spec_vnode_vops, &nvp);
+       error = getnewvnode(VT_NON, NULL, spec_vnode_vops, &nvp, 0, 0);
        if (error) {
                *vpp = NULLVP;
                return (error);
@@ -2087,7 +2092,6 @@ vclean(struct vnode *vp, lwkt_tokref_t vlock, int flags, struct thread *td)
        }
 
        cache_purge(vp);
-       vp->v_vnlock = NULL;
        vmaybefree(vp);
        
        /*
@@ -3069,10 +3073,10 @@ vn_pollgone(struct vnode *vp)
 static int     sync_fsync (struct  vop_fsync_args *);
 static int     sync_inactive (struct  vop_inactive_args *);
 static int     sync_reclaim  (struct  vop_reclaim_args *);
-#define sync_lock ((int (*) (struct  vop_lock_args *))vop_nolock)
-#define sync_unlock ((int (*) (struct  vop_unlock_args *))vop_nounlock)
+#define sync_lock ((int (*) (struct  vop_lock_args *))vop_stdlock)
+#define sync_unlock ((int (*) (struct  vop_unlock_args *))vop_stdunlock)
 static int     sync_print (struct vop_print_args *);
-#define sync_islocked ((int(*) (struct vop_islocked_args *))vop_noislocked)
+#define sync_islocked ((int(*) (struct vop_islocked_args *))vop_stdislocked)
 
 static struct vop_ops *sync_vnode_vops;
 static struct vnodeopv_entry_desc sync_vnodeop_entries[] = {
@@ -3109,7 +3113,8 @@ vfs_allocate_syncvnode(struct mount *mp)
        int error;
 
        /* Allocate a new vnode */
-       if ((error = getnewvnode(VT_VFS, mp, sync_vnode_vops, &vp)) != 0) {
+       error = getnewvnode(VT_VFS, mp, sync_vnode_vops, &vp, 0, 0);
+       if (error) {
                mp->mnt_syncer = NULL;
                return (error);
        }
@@ -3195,6 +3200,7 @@ sync_fsync(struct vop_fsync_args *ap)
 static int
 sync_inactive(struct vop_inactive_args *ap)
 {
+       VOP_UNLOCK(ap->a_vp, NULL, 0, ap->a_td);
        vgone(ap->a_vp);
        return (0);
 }
@@ -3234,8 +3240,7 @@ sync_print(struct vop_print_args *ap)
        struct vnode *vp = ap->a_vp;
 
        printf("syncer vnode");
-       if (vp->v_vnlock != NULL)
-               lockmgr_printinfo(vp->v_vnlock);
+       lockmgr_printinfo(&vp->v_lock);
        printf("\n");
        return (0);
 }
index 7ea1e08..1d49359 100644 (file)
@@ -32,7 +32,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/vfs_vopops.c,v 1.3 2004/08/25 19:14:39 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_vopops.c,v 1.4 2004/08/28 19:02:05 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -196,7 +196,8 @@ static int VOFFNAME(rename)[] = {
 };
 VNODEOP_DESC_INIT(rename, 
        VDESC_VP0_WILLRELE|VDESC_VP1_WILLRELE|
-        VDESC_VP2_WILLRELE|VDESC_VP3_WILLRELE,
+        VDESC_VP2_WILLRELE|VDESC_VP3_WILLRELE|
+        VDESC_VP2_WILLUNLOCK|VDESC_VP3_WILLUNLOCK, /* tdvp and tvp */
        VOFFNAME(rename),
        VDESC_NO_OFFSET,
        VDESC_NO_OFFSET,
index 9e91234..b538524 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     @(#)lock.h      8.12 (Berkeley) 5/19/95
  * $FreeBSD: src/sys/sys/lock.h,v 1.17.2.3 2001/12/25 01:44:44 dillon Exp $
- * $DragonFly: src/sys/sys/lock.h,v 1.8 2004/03/01 06:33:19 dillon Exp $
+ * $DragonFly: src/sys/sys/lock.h,v 1.9 2004/08/28 19:02:07 dillon Exp $
  */
 
 #ifndef        _SYS_LOCK_H_
@@ -189,8 +189,8 @@ struct lock {
 void dumplockinfo(struct lock *lkp);
 struct proc;
 
-void   lockinit (struct lock *, int prio, char *wmesg, int timo,
-                       int flags);
+void   lockinit (struct lock *, int prio, char *wmesg, int timo, int flags);
+void   lockreinit (struct lock *, int prio, char *wmesg, int timo, int flags);
 #ifdef DEBUG_LOCKS
 int    debuglockmgr (struct lock *, u_int flags,
                        struct lwkt_tokref *, struct thread *p,
index f16582e..f30bb40 100644 (file)
@@ -62,7 +62,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/sys/namecache.h,v 1.6 2004/07/16 05:51:57 dillon Exp $
+ * $DragonFly: src/sys/sys/namecache.h,v 1.7 2004/08/28 19:02:07 dillon Exp $
  */
 
 #ifndef _SYS_NAMECACHE_H_
@@ -80,6 +80,18 @@ TAILQ_HEAD(namecache_list, namecache);
  * The namecache is disjoint, there may not always be a path to the system
  * root through nc_parent links.  If a namecache entry has no parent, that
  * entry will not be hashed and can only be 'found' via '.' or '..'.
+ *
+ * Because the namecache structure maintains the path through mount points,
+ * null, and union mounts, and other VFS overlays, several namecache
+ * structures may pass through the same vnode.  Also note that namespaces
+ * relating to non-existant (i.e. not-yet-created) files/directories may be
+ * locked.  Lock coherency is achieved by requiring that the particular
+ * namecache record whos parent represents the physical directory in which
+ * the namespace operation is to occur be the one that is locked.  In 
+ * overlay cases, the (union, nullfs) VFS, or in namei when crossing a mount
+ * point, may have to obtain multiple namespace record locks to avoid
+ * confusion, but only the one representing the physical directory is passed
+ * into lower layer VOP calls.
  */
 struct namecache {
     LIST_ENTRY(namecache) nc_hash;     /* hash chain (nc_parent,name) */
@@ -94,6 +106,9 @@ struct namecache {
     u_char     nc_unused;
     char       *nc_name;               /* Separately allocated seg name */
     int                nc_timeout;             /* compared against ticks, or 0 */
+#if 0
+    struct lockmgr nc_lock;            /* namespace lock */
+#endif
 };
 
 typedef struct namecache *namecache_t;
@@ -101,12 +116,12 @@ typedef struct namecache *namecache_t;
 /*
  * Flags in namecache.nc_flag (u_char)
  */
-#define NCF_NEGATIVE   0x01    /* negative entry */
-#define NCF_WHITEOUT   0x02    /* negative entry corresponds to whiteout */
-#define NCF_UNRESOLVED 0x04    /* invalid or unresolved entry */
-#define NCF_MOUNTPT    0x08    /* mount point */
-#define NCF_ROOT       0x10    /* namecache root (static) */
-#define NCF_HASHED     0x20    /* namecache entry in hash table */
+#define NCF_NEGATIVE   0x0001  /* negative entry */
+#define NCF_WHITEOUT   0x0002  /* negative entry corresponds to whiteout */
+#define NCF_UNRESOLVED 0x0004  /* invalid or unresolved entry */
+#define NCF_MOUNTPT    0x0008  /* mount point */
+#define NCF_ROOT       0x0010  /* namecache root (static) */
+#define NCF_HASHED     0x0020  /* namecache entry in hash table */
 
 #define CINV_SELF      0x0001  /* invalidate a specific (dvp,vp) entry */
 #define CINV_CHILDREN  0x0002  /* invalidate all children of vp */
index 4dc06bd..e6b1c54 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)vnode.h     8.7 (Berkeley) 2/4/94
  * $FreeBSD: src/sys/sys/vnode.h,v 1.111.2.19 2002/12/29 18:19:53 dillon Exp $
- * $DragonFly: src/sys/sys/vnode.h,v 1.20 2004/08/17 18:57:32 dillon Exp $
+ * $DragonFly: src/sys/sys/vnode.h,v 1.21 2004/08/28 19:02:07 dillon Exp $
  */
 
 #ifndef _SYS_VNODE_H_
@@ -73,10 +73,17 @@ TAILQ_HEAD(buflists, buf);
  *    locked by the v_interlock token.
  * v_pollinfo is locked by the lock contained inside it.
  *
- * XXX note: v_opencount currently only used by specfs.  It should be used
- * universally.
+ * NOTE: XXX v_opencount currently only used by specfs.  It should be used
+ *      universally.  
+ *
+ * NOTE: The v_vnlock pointer is now an embedded lock structure, v_lock.
+ *      v_lock is currently locked exclusively for writes but when a
+ *      range lock is added later on it will be locked shared for writes
+ *      and a range will be exclusively reserved in the rangelock space.
+ *      v_lock is currently locked exclusively for directory modifying
+ *      operations but when we start locking namespaces it will no longer
+ *      be used for that function, only for the actual I/O on the directory.
  */
-
 struct vnode {
        u_long  v_flag;                         /* vnode flags (see below) */
        int     v_usecount;                     /* reference count of users */
@@ -110,7 +117,7 @@ struct vnode {
        int     v_clen;                         /* length of current cluster */
        struct vm_object *v_object;             /* Place to store VM object */
        lwkt_token_t v_interlock;               /* lock on usecount and flag */
-       struct  lock *v_vnlock;                 /* used for non-locking fs's */
+       struct  lock v_lock;                    /* file/dir ops lock */
        enum    vtagtype v_tag;                 /* type of underlying data */
        void    *v_data;                        /* private data for fs */
        struct namecache_list v_namecache;      /* associated nc entries */
@@ -277,14 +284,26 @@ extern void       (*lease_updatetime) (int deltat);
 /*
  * Flags for vdesc_flags:
  */
-#define        VDESC_MAX_VPS           16
-/* Low order 16 flag bits are reserved for willrele flags for vp arguments. */
-#define        VDESC_VP0_WILLRELE      0x0001
-#define        VDESC_VP1_WILLRELE      0x0002
-#define        VDESC_VP2_WILLRELE      0x0004
-#define        VDESC_VP3_WILLRELE      0x0008
-#define        VDESC_NOMAP_VPP         0x0100
-#define        VDESC_VPP_WILLRELE      0x0200
+#define        VDESC_MAX_VPS           8
+/* Low order 8 flag bits are reserved for willrele flags for vp arguments. */
+#define        VDESC_VP0_WILLRELE      0x00000001
+#define        VDESC_VP1_WILLRELE      0x00000002
+#define        VDESC_VP2_WILLRELE      0x00000004
+#define        VDESC_VP3_WILLRELE      0x00000008
+#define        VDESC_VP4_WILLRELE      0x00000010
+#define        VDESC_VP5_WILLRELE      0x00000020
+#define        VDESC_VP6_WILLRELE      0x00000040
+#define        VDESC_VP7_WILLRELE      0x00000080
+#define        VDESC_NOMAP_VPP         0x00000100
+#define        VDESC_VPP_WILLRELE      0x00000200
+#define VDESC_VP0_WILLUNLOCK   0x00010000
+#define VDESC_VP1_WILLUNLOCK   0x00020000
+#define VDESC_VP2_WILLUNLOCK   0x00040000
+#define VDESC_VP3_WILLUNLOCK   0x00080000
+#define VDESC_VP4_WILLUNLOCK   0x00100000
+#define VDESC_VP5_WILLUNLOCK   0x00200000
+#define VDESC_VP6_WILLUNLOCK   0x00400000
+#define VDESC_VP7_WILLUNLOCK   0x00800000
 
 /*
  * VDESC_NO_OFFSET is used to identify the end of the offset list
@@ -483,8 +502,8 @@ void        v_release_rdev(struct vnode *vp);
 int    bdevvp (dev_t dev, struct vnode **vpp);
 void   cvtstat (struct stat *st, struct ostat *ost);
 void   cvtnstat (struct stat *sb, struct nstat *nsb);
-int    getnewvnode (enum vtagtype tag,
-           struct mount *mp, struct vop_ops *ops, struct vnode **vpp);
+int    getnewvnode (enum vtagtype tag, struct mount *mp, struct vop_ops *ops,
+                   struct vnode **vpp, int timo, int lkflags);
 int    lease_check (struct vop_lease_args *ap);
 int    spec_vnoperate (struct vop_generic_args *);
 int    speedup_syncer (void);
@@ -541,15 +560,12 @@ int       vn_writechk (struct vnode *vp);
 int    vop_stdbwrite (struct vop_bwrite_args *ap);
 int    vop_stdislocked (struct vop_islocked_args *ap);
 int    vop_stdlock (struct vop_lock_args *ap);
+int    vop_stdrlock (struct vop_lock_args *ap);
 int    vop_stdunlock (struct vop_unlock_args *ap);
-int    vop_noislocked (struct vop_islocked_args *ap);
-int    vop_nolock (struct vop_lock_args *ap);
 int    vop_nopoll (struct vop_poll_args *ap);
-int    vop_nounlock (struct vop_unlock_args *ap);
 int    vop_stdpathconf (struct vop_pathconf_args *ap);
 int    vop_stdpoll (struct vop_poll_args *ap);
 int    vop_stdrevoke (struct vop_revoke_args *ap);
-int    vop_sharedlock (struct vop_lock_args *ap);
 int    vop_eopnotsupp (struct vop_generic_args *ap);
 int    vop_ebadf (struct vop_generic_args *ap);
 int    vop_einval (struct vop_generic_args *ap);
index a031060..a8401b7 100644 (file)
@@ -28,7 +28,7 @@
  * 
  *     @(#) src/sys/coda/cnode.h,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ 
  * $FreeBSD: src/sys/coda/cnode.h,v 1.7 1999/08/28 00:40:52 peter Exp $
- * $DragonFly: src/sys/vfs/coda/Attic/cnode.h,v 1.3 2003/08/07 21:17:40 dillon Exp $
+ * $DragonFly: src/sys/vfs/coda/Attic/cnode.h,v 1.4 2004/08/28 19:02:08 dillon Exp $
  * 
  */
 
@@ -103,7 +103,6 @@ struct cnode {
     struct vnode       *c_vnode;
     u_short             c_flags;       /* flags (see below) */
     ViceFid             c_fid;         /* file handle */
-    struct lock                 c_lock;        /* new lock protocol */
     struct vnode       *c_ovp;         /* open vnode pointer */
     u_short             c_ocount;      /* count of openers */
     u_short             c_owrite;      /* count of open for write */
index 2e33bc0..d48a556 100644 (file)
@@ -28,7 +28,7 @@
  * 
  *     @(#) src/sys/coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
  * $FreeBSD: src/sys/coda/coda_vnops.c,v 1.22.2.1 2001/06/29 16:26:22 shafeeq Exp $
- * $DragonFly: src/sys/vfs/coda/Attic/coda_vnops.c,v 1.18 2004/08/17 18:57:32 dillon Exp $
+ * $DragonFly: src/sys/vfs/coda/Attic/coda_vnops.c,v 1.19 2004/08/28 19:02:08 dillon Exp $
  * 
  */
 
@@ -895,7 +895,7 @@ coda_inactive(void *v)
            printf("coda_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n",
                   vp->v_usecount, vp, cp);
 #endif
-       lockmgr(&cp->c_lock, LK_RELEASE, NULL, td);
+       lockmgr(&vp->v_lock, LK_RELEASE, NULL, td);
     } else {
 #ifdef OLD_DIAGNOSTIC
        if (CTOV(cp)->v_usecount) {
@@ -1746,9 +1746,9 @@ coda_lock(void *v)
     }
 
 #ifndef        DEBUG_LOCKS
-    return (lockmgr(&cp->c_lock, ap->a_flags, ap->a_vlock, td));
+    return (lockmgr(&vp->v_lock, ap->a_flags, ap->a_vlock, td));
 #else
-    return (debuglockmgr(&cp->c_lock, ap->a_flags, ap->a_vlock, td,
+    return (debuglockmgr(&vp->v_lock, ap->a_flags, ap->a_vlock, td,
                         "coda_lock", vp->filename, vp->line));
 #endif
 }
@@ -1770,7 +1770,7 @@ coda_unlock(void *v)
                  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
     }
 
-    return (lockmgr(&cp->c_lock, ap->a_flags | LK_RELEASE, ap->a_vlock, td));
+    return (lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, ap->a_vlock, td));
 }
 
 int
@@ -1778,10 +1778,9 @@ coda_islocked(void *v)
 {
 /* true args */
     struct vop_islocked_args *ap = v;
-    struct cnode *cp = VTOC(ap->a_vp);
     ENTRY;
 
-    return (lockstatus(&cp->c_lock, ap->a_td));
+    return (lockstatus(&ap->a_vp->v_lock, ap->a_td));
 }
 
 /* How one looks up a vnode given a device/inode pair: */
@@ -1898,10 +1897,9 @@ make_coda_node(ViceFid *fid, struct mount *vfsp, short type)
        struct vnode *vp;
        
        cp = coda_alloc();
-       lockinit(&cp->c_lock, 0, "cnode", 0, 0);
        cp->c_fid = *fid;
        
-       err = getnewvnode(VT_CODA, vfsp, vfsp->mnt_vn_ops, &vp);  
+       err = getnewvnode(VT_CODA, vfsp, vfsp->mnt_vn_ops, &vp, 0, 0);
        if (err) {                                                
            panic("coda: getnewvnode returned error %d\n", err);   
        }                                                         
index 6e4912a..44c8af8 100644 (file)
@@ -36,7 +36,7 @@
  *     @(#)fdesc_vnops.c       8.9 (Berkeley) 1/21/94
  *
  * $FreeBSD: src/sys/miscfs/fdesc/fdesc_vnops.c,v 1.47.2.1 2001/10/22 22:49:26 chris Exp $
- * $DragonFly: src/sys/vfs/fdesc/fdesc_vnops.c,v 1.13 2004/08/17 18:57:33 dillon Exp $
+ * $DragonFly: src/sys/vfs/fdesc/fdesc_vnops.c,v 1.14 2004/08/28 19:02:10 dillon Exp $
  */
 
 /*
@@ -130,7 +130,7 @@ loop:
         */
        MALLOC(fd, struct fdescnode *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
 
-       error = getnewvnode(VT_FDESC, mp, mp->mnt_vn_ops, vpp);
+       error = getnewvnode(VT_FDESC, mp, mp->mnt_vn_ops, vpp, 0, 0);
        if (error) {
                FREE(fd, M_TEMP);
                goto out;
index 493beb3..a61432f 100644 (file)
@@ -38,7 +38,7 @@
  *
  *     @(#)ffs_vfsops.c        8.8 (Berkeley) 4/18/94
  *     $FreeBSD: src/sys/gnu/ext2fs/ext2_vfsops.c,v 1.63.2.7 2002/07/01 00:18:51 iedowse Exp $
- *     $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vfsops.c,v 1.18 2004/08/17 18:57:33 dillon Exp $
+ *     $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vfsops.c,v 1.19 2004/08/28 19:02:12 dillon Exp $
  */
 
 #include "opt_quota.h"
@@ -1053,7 +1053,7 @@ restart:
        MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2NODE, M_WAITOK);
 
        /* Allocate a new vnode/inode. */
-       if ((error = getnewvnode(VT_UFS, mp, mp->mnt_vn_ops, &vp)) != 0) {
+       if ((error = getnewvnode(VT_UFS, mp, mp->mnt_vn_ops, &vp, 0, 0)) != 0) {
                if (ext2fs_inode_hash_lock < 0)
                        wakeup(&ext2fs_inode_hash_lock);
                ext2fs_inode_hash_lock = 0;
@@ -1062,7 +1062,6 @@ restart:
                return (error);
        }
        bzero((caddr_t)ip, sizeof(struct inode));
-       lockinit(&ip->i_lock, 0, "ext2in", 0, 0);
        vp->v_data = ip;
        ip->i_vnode = vp;
        ip->i_e2fs = fs = ump->um_e2fs;
index 9ba8ed9..9cfa5d0 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/hpfs/hpfs.h,v 1.1 1999/12/09 19:09:58 semenu Exp $
- * $DragonFly: src/sys/vfs/hpfs/hpfs.h,v 1.12 2004/08/17 18:57:33 dillon Exp $
+ * $DragonFly: src/sys/vfs/hpfs/hpfs.h,v 1.13 2004/08/28 19:02:14 dillon Exp $
  */
 
 /*#define HPFS_DEBUG 10*/
@@ -335,7 +335,6 @@ struct hpfsmount {
 #define        H_PARCHANGE     0x0008          /* parent node date was changed */
 #define        H_INVAL         0x0010          /* Invalid node */
 struct hpfsnode {
-       struct lock     h_lock;         /* Must be first, for std vops */
        struct lwkt_token h_interlock;
 
        LIST_ENTRY(hpfsnode)    h_hash;
index 51d555a..5b83bfb 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/hpfs/hpfs_vfsops.c,v 1.3.2.2 2001/12/25 01:44:45 dillon Exp $
- * $DragonFly: src/sys/vfs/hpfs/hpfs_vfsops.c,v 1.19 2004/08/17 18:57:33 dillon Exp $
+ * $DragonFly: src/sys/vfs/hpfs/hpfs_vfsops.c,v 1.20 2004/08/28 19:02:14 dillon Exp $
  */
 
 
@@ -613,7 +613,8 @@ hpfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
        MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode), 
                M_HPFSNO, M_WAITOK);
 
-       error = getnewvnode(VT_HPFS, hpmp->hpm_mp, hpmp->hpm_mp->mnt_vn_ops, &vp);
+       error = getnewvnode(VT_HPFS, hpmp->hpm_mp, hpmp->hpm_mp->mnt_vn_ops,
+                           &vp, VLKTIMEOUT, 0);
        if (error) {
                printf("hpfs_vget: can't get new vnode\n");
                FREE(hp, M_HPFSNO);
@@ -628,7 +629,6 @@ hpfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
                vp->v_flag |= VROOT;
 
        lwkt_token_init(&hp->h_interlock);
-       lockinit(&hp->h_lock, 0, "hpnode", VLKTIMEOUT, 0);
 
        hp->h_flag = H_INVAL;
        hp->h_vp = vp;
index 7dc1574..80e61c6 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/hpfs/hpfs_vnops.c,v 1.2.2.2 2002/01/15 18:35:09 semenu Exp $
- * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.16 2004/08/17 18:57:33 dillon Exp $
+ * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.17 2004/08/28 19:02:14 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -678,7 +678,7 @@ hpfs_print(struct vop_print_args *ap)
        struct hpfsnode *hp = VTOHP(vp);
 
        printf("tag VT_HPFS, ino 0x%x",hp->h_no);
-       lockmgr_printinfo(&hp->h_lock);
+       lockmgr_printinfo(&vp->v_lock);
        printf("\n");
        return (0);
 }
index 02a7b5e..7e5c77f 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)cd9660_node.c       8.2 (Berkeley) 1/23/94
  * $FreeBSD: src/sys/isofs/cd9660/cd9660_node.c,v 1.29.2.1 2000/07/08 14:35:56 bp Exp $
- * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.c,v 1.10 2004/04/12 23:18:55 cpressey Exp $
+ * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.c,v 1.11 2004/08/28 19:02:15 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -72,8 +72,12 @@ static unsigned      cd9660_chars2ui (unsigned char *begin, int len);
 int
 cd9660_init(struct vfsconf *vfsp)
 {
-
-       isohashtbl = hashinit(desiredvnodes, M_ISOFSMNT, &isohash);
+       isohash = 16;
+       while (isohash < desiredvnodes)
+               isohash <<= 1;
+       isohashtbl = malloc(sizeof(void *) * isohash,
+                           M_ISOFSMNT, M_WAITOK|M_ZERO);
+       --isohash;
        lwkt_token_init(&cd9660_ihash_token);
        return (0);
 }
@@ -130,25 +134,28 @@ loop:
 }
 
 /*
- * Insert the inode into the hash table, and return it locked.
+ * Insert the inode into the hash table, return 0 on success, non-zero
+ * if the inode has already been found to be in the hash table.
  */
-void
+int
 cd9660_ihashins(struct iso_node *ip)
 {
-       struct thread *td = curthread;  /* XXX */
        struct iso_node **ipp, *iq;
        lwkt_tokref ilock;
 
        lwkt_gettoken(&ilock, &cd9660_ihash_token);
        ipp = &isohashtbl[INOHASH(ip->i_dev, ip->i_number)];
-       if ((iq = *ipp) != NULL)
-               iq->i_prev = &ip->i_next;
-       ip->i_next = iq;
-       ip->i_prev = ipp;
+       while ((iq = *ipp) != NULL) {
+               if (iq->i_dev == ip->i_dev && iq->i_number == ip->i_number) {
+                       lwkt_reltoken(&ilock);
+                       return(EBUSY);
+               }
+               ipp = &iq->i_next;
+       }
+       ip->i_next = NULL;
        *ipp = ip;
        lwkt_reltoken(&ilock);
-
-       lockmgr(&ip->i_lock, LK_EXCLUSIVE, NULL, td);
+       return(0);
 }
 
 /*
@@ -157,17 +164,19 @@ cd9660_ihashins(struct iso_node *ip)
 static void
 cd9660_ihashrem(struct iso_node *ip)
 {
-       struct iso_node *iq;
+       struct iso_node **ipp, *iq;
        lwkt_tokref ilock;
 
        lwkt_gettoken(&ilock, &cd9660_ihash_token);
-       if ((iq = ip->i_next) != NULL)
-               iq->i_prev = ip->i_prev;
-       *ip->i_prev = iq;
-#ifdef DIAGNOSTIC
+       ipp = &isohashtbl[INOHASH(ip->i_dev, ip->i_number)];
+       while ((iq = *ipp) != NULL) {
+               if (ip == iq)
+                       break;
+               ipp = &iq->i_next;
+       }
+       KKASSERT(ip == iq);
+       *ipp = ip->i_next;
        ip->i_next = NULL;
-       ip->i_prev = NULL;
-#endif
        lwkt_reltoken(&ilock);
 }
 
@@ -188,13 +197,14 @@ cd9660_inactive(struct vop_inactive_args *ap)
        if (prtactive && vp->v_usecount != 0)
                vprint("cd9660_inactive: pushing active", vp);
 
-       ip->i_flag = 0;
+       if (ip)
+               ip->i_flag = 0;
        VOP_UNLOCK(vp, NULL, 0, td);
        /*
         * If we are done with the inode, reclaim it
         * so that it can be reused immediately.
         */
-       if (ip->inode.iso_mode == 0)
+       if (ip == NULL || ip->inode.iso_mode == 0)
                vrecycle(vp, NULL, td);
        return error;
 }
@@ -213,19 +223,19 @@ cd9660_reclaim(struct vop_reclaim_args *ap)
        if (prtactive && vp->v_usecount != 0)
                vprint("cd9660_reclaim: pushing active", vp);
        /*
-        * Remove the inode from its hash chain.
-        */
-       cd9660_ihashrem(ip);
-       /*
-        * Purge old data structures associated with the inode.
+        * Remove the inode from its hash chain and purge namecache
+        * data associated with the vnode.
         */
        cache_purge(vp);
-       if (ip->i_devvp) {
-               vrele(ip->i_devvp);
-               ip->i_devvp = 0;
-       }
-       FREE(vp->v_data, M_ISOFSNODE);
        vp->v_data = NULL;
+       if (ip) {
+               cd9660_ihashrem(ip);
+               if (ip->i_devvp) {
+                       vrele(ip->i_devvp);
+                       ip->i_devvp = 0;
+               }
+               free(ip, M_ISOFSNODE);
+       }
        return (0);
 }
 
index c064e39..8833c6f 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)cd9660_node.h       8.6 (Berkeley) 5/14/95
  * $FreeBSD: src/sys/isofs/cd9660/cd9660_node.h,v 1.20 1999/12/29 04:54:37 peter Exp $
- * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.h,v 1.4 2004/05/03 16:06:26 joerg Exp $
+ * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.h,v 1.5 2004/08/28 19:02:15 dillon Exp $
  */
 
 #include <sys/lockf.h>
@@ -64,8 +64,7 @@ typedef       struct  {
 
 
 struct iso_node {
-       struct  lock i_lock;    /* node lock > Keep this first< */
-       struct  iso_node *i_next, **i_prev;     /* hash chain */
+       struct  iso_node *i_next; /* hash chain */
        struct  vnode *i_vnode; /* vnode associated with this inode */
        struct  vnode *i_devvp; /* vnode for block I/O */
        u_long  i_flag;         /* see below */
@@ -122,7 +121,7 @@ void cd9660_defattr (struct iso_directory_record *,
 void cd9660_deftstamp (struct iso_directory_record *,
                        struct iso_node *, struct buf *, enum ISO_FTYPE);
 struct vnode *cd9660_ihashget (dev_t, ino_t);
-void cd9660_ihashins (struct iso_node *);
+int cd9660_ihashins (struct iso_node *);
 int cd9660_tstamp_conv7 (u_char *, struct timespec *, enum ISO_FTYPE);
 int cd9660_tstamp_conv17 (u_char *, struct timespec *);
 
index d2d219c..e5eeb19 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)cd9660_vfsops.c     8.18 (Berkeley) 5/22/95
  * $FreeBSD: src/sys/isofs/cd9660/cd9660_vfsops.c,v 1.74.2.7 2002/04/08 09:39:29 bde Exp $
- * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vfsops.c,v 1.19 2004/08/17 18:57:33 dillon Exp $
+ * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vfsops.c,v 1.20 2004/08/28 19:02:15 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -695,6 +695,7 @@ int
 cd9660_vget_internal(struct mount *mp, ino_t ino, struct vnode **vpp,
                     int relocated, struct iso_directory_record *isodir)
 {
+       struct thread *td = curthread;
        struct iso_mnt *imp;
        struct iso_node *ip;
        struct buf *bp;
@@ -704,30 +705,35 @@ cd9660_vget_internal(struct mount *mp, ino_t ino, struct vnode **vpp,
 
        imp = VFSTOISOFS(mp);
        dev = imp->im_dev;
+again:
        if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP)
                return (0);
 
        /* Allocate a new vnode/iso_node. */
-       if ((error = getnewvnode(VT_ISOFS, mp, mp->mnt_vn_ops, &vp)) != 0) {
+       error = getnewvnode(VT_ISOFS, mp, mp->mnt_vn_ops, &vp, 0, 0);
+       if (error) {
                *vpp = NULLVP;
                return (error);
        }
        MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE,
            M_WAITOK);
        bzero((caddr_t)ip, sizeof(struct iso_node));
-       lockinit(&ip->i_lock, 0, "isonode", 0, 0);
-       vp->v_data = ip;
+       lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL, td);
        ip->i_vnode = vp;
        ip->i_dev = dev;
        ip->i_number = ino;
 
        /*
-        * Put it onto its hash chain and lock it so that other requests for
-        * this inode will block if they arrive while we are sleeping waiting
-        * for old data structures to be purged or for the contents of the
-        * disk portion of this inode to be read.
+        * Insert it into the inode hash table and check for a collision.
+        * If a collision occurs, throw away the vnode and try again.
         */
-       cd9660_ihashins(ip);
+       if (cd9660_ihashins(ip) != 0) {
+               printf("debug: cd9660 ihashins collision, retrying\n");
+               vput(vp);
+               free(ip, M_ISOFSNODE);
+               goto again;
+       }
+       vp->v_data = ip;
 
        if (isodir == 0) {
                int lbn, off;
index b9b65be..abc1e07 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)mfs_vfsops.c        8.11 (Berkeley) 6/19/95
  * $FreeBSD: src/sys/ufs/mfs/mfs_vfsops.c,v 1.81.2.3 2001/07/04 17:35:21 tegge Exp $
- * $DragonFly: src/sys/vfs/mfs/mfs_vfsops.c,v 1.16 2004/08/13 17:51:11 dillon Exp $
+ * $DragonFly: src/sys/vfs/mfs/mfs_vfsops.c,v 1.17 2004/08/28 19:02:17 dillon Exp $
  */
 
 
@@ -290,7 +290,7 @@ mfs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp,
         */
        MALLOC(mfsp, struct mfsnode *, sizeof *mfsp, M_MFSNODE, M_WAITOK);
 
-       err = getnewvnode(VT_MFS, NULL, mfs_vnode_vops, &devvp);
+       err = getnewvnode(VT_MFS, NULL, mfs_vnode_vops, &devvp, 0, 0);
        if (err) {
                FREE(mfsp, M_MFSNODE);
                goto error_1;
index d9f6789..4802bcd 100644 (file)
@@ -1,5 +1,5 @@
 /* $FreeBSD: src/sys/msdosfs/denode.h,v 1.20 1999/12/29 04:54:52 peter Exp $ */
-/* $DragonFly: src/sys/vfs/msdosfs/denode.h,v 1.7 2004/08/17 18:57:34 dillon Exp $ */
+/* $DragonFly: src/sys/vfs/msdosfs/denode.h,v 1.8 2004/08/28 19:02:18 dillon Exp $ */
 /*     $NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $   */
 
 /*-
@@ -136,9 +136,7 @@ struct fatcache {
  * contained within a vnode.
  */
 struct denode {
-       struct lock de_lock;    /* denode lock >Keep this first< */
        struct denode *de_next; /* Hash chain forward */
-       struct denode **de_prev; /* Hash chain back */
        struct vnode *de_vnode; /* addr of vnode we are part of */
        struct vnode *de_devvp; /* vnode of blk dev we live on */
        u_long de_flag;         /* flag bits */
@@ -275,7 +273,7 @@ int readep (struct msdosfsmount *pmp, u_long dirclu, u_long dirofs,  struct buf
 int readde (struct denode *dep, struct buf **bpp, struct direntry **epp);
 int deextend (struct denode *dep, u_long length);
 int fillinusemap (struct msdosfsmount *pmp);
-void reinsert (struct denode *dep);
+void msdosfs_reinsert(struct denode *ip, u_long new_dirclust, u_long new_diroffset);
 int dosdirempty (struct denode *dep);
 int createde (struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp);
 int deupdat (struct denode *dep, int waitfor);
index a323a3f..6e727c4 100644 (file)
@@ -1,5 +1,5 @@
 /* $FreeBSD: src/sys/msdosfs/msdosfs_denode.c,v 1.47.2.3 2002/08/22 16:20:15 trhodes Exp $ */
-/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_denode.c,v 1.14 2004/08/17 18:57:34 dillon Exp $ */
+/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_denode.c,v 1.15 2004/08/28 19:02:18 dillon Exp $ */
 /*     $NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $  */
 
 /*-
@@ -67,6 +67,9 @@
 #include "denode.h"
 #include "fat.h"
 
+static int msdosfs_hashins (struct denode *dep);
+static void msdosfs_hashrem (struct denode *dep);
+
 static MALLOC_DEFINE(M_MSDOSFSNODE, "MSDOSFS node", "MSDOSFS vnode private part");
 
 static struct denode **dehashtbl;
@@ -93,16 +96,18 @@ union _qcvt {
 }
 
 static struct denode *
-               msdosfs_hashget (dev_t dev, u_long dirclust,
-                                    u_long diroff);
-static void    msdosfs_hashins (struct denode *dep);
-static void    msdosfs_hashrem (struct denode *dep);
+               msdosfs_hashget (dev_t dev, u_long dirclust, u_long diroff);
 
 /*ARGSUSED*/
 int 
 msdosfs_init(struct vfsconf *vfsp)
 {
-       dehashtbl = hashinit(desiredvnodes/2, M_MSDOSFSMNT, &dehash);
+       dehash = 16;
+       while (dehash < desiredvnodes)
+               dehash <<= 1;
+       dehashtbl = malloc(sizeof(void *) * dehash, M_MSDOSFSMNT,
+                          M_WAITOK|M_ZERO);
+       --dehash;
        lwkt_token_init(&dehash_token);
        return (0);
 }
@@ -136,6 +141,7 @@ loop:
                }
                vp = DETOV(dep);
                lwkt_gettoken(&vlock, vp->v_interlock);
+
                /*
                 * We must check to see if the inode has been ripped
                 * out from under us after blocking.
@@ -161,7 +167,8 @@ loop:
        return (NULL);
 }
 
-static void
+static
+int
 msdosfs_hashins(struct denode *dep)
 {
        struct denode **depp, *deq;
@@ -169,30 +176,51 @@ msdosfs_hashins(struct denode *dep)
 
        lwkt_gettoken(&ilock, &dehash_token);
        depp = &DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
-       deq = *depp;
-       if (deq)
-               deq->de_prev = &dep->de_next;
-       dep->de_next = deq;
-       dep->de_prev = depp;
+       while ((deq = *depp) != NULL) {
+               if (deq->de_dev == dep->de_dev &&
+                   deq->de_dirclust == dep->de_dirclust &&
+                   deq->de_diroffset == dep->de_diroffset) {
+                       lwkt_reltoken(&ilock);
+                       return(EBUSY);
+               }
+               depp = &deq->de_next;
+       }
+       dep->de_next = NULL;
        *depp = dep;
        lwkt_reltoken(&ilock);
+       return(0);
 }
 
-static void
+static
+void
 msdosfs_hashrem(struct denode *dep)
 {
-       struct denode *deq;
+       struct denode **depp, *deq;
        lwkt_tokref ilock;
 
        lwkt_gettoken(&ilock, &dehash_token);
-       deq = dep->de_next;
-       if (deq)
-               deq->de_prev = dep->de_prev;
-       *dep->de_prev = deq;
-#ifdef DIAGNOSTIC
+       depp = &DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
+       while ((deq = *depp) != NULL) {
+               if (dep == deq)
+                       break;
+               depp = &deq->de_next;
+       }
+       KKASSERT(dep == deq);
+       *depp = dep->de_next;
        dep->de_next = NULL;
-       dep->de_prev = NULL;
-#endif
+       lwkt_reltoken(&ilock);
+}
+
+void
+msdosfs_reinsert(struct denode *ip, u_long new_dirclust, u_long new_diroffset)
+{
+       lwkt_tokref ilock;
+
+       lwkt_gettoken(&ilock, &dehash_token);
+       msdosfs_hashrem(ip);
+       ip->de_dirclust = new_dirclust;
+       ip->de_diroffset = new_diroffset;
+       msdosfs_hashins(ip);
        lwkt_reltoken(&ilock);
 }
 
@@ -236,6 +264,7 @@ deget(struct msdosfsmount *pmp,     /* so we know the maj/min number */
        if (FAT32(pmp) && dirclust == MSDOSFSROOT)
                dirclust = pmp->pm_rootdirblk;
 
+again:
        /*
         * See if the denode is in the denode cache. Use the location of
         * the directory entry to compute the hash value. For subdir use
@@ -265,16 +294,24 @@ deget(struct msdosfsmount *pmp,   /* so we know the maj/min number */
         * Directory entry was not in cache, have to create a vnode and
         * copy it from the passed disk buffer.
         */
+
        /* getnewvnode() does a vref() on the vnode */
-       error = getnewvnode(VT_MSDOSFS, mntp, mntp->mnt_vn_ops, &nvp);
+       error = getnewvnode(VT_MSDOSFS, mntp, mntp->mnt_vn_ops, &nvp,
+                           VLKTIMEOUT, 0);
        if (error) {
                *depp = NULL;
                FREE(ldep, M_MSDOSFSNODE);
                return error;
        }
+
+       /*
+        * Lock the denode so that it can't be accessed until we've read
+        * it in and have done what we need to it.
+        */
+       if (lockmgr(&nvp->v_lock, LK_EXCLUSIVE, NULL, td))
+               panic("deget: unexpected lock failure");
+
        bzero((caddr_t)ldep, sizeof *ldep);
-       lockinit(&ldep->de_lock, 0, "denode", VLKTIMEOUT, 0);
-       nvp->v_data = ldep;
        ldep->de_vnode = nvp;
        ldep->de_flag = 0;
        ldep->de_devvp = 0;
@@ -284,19 +321,16 @@ deget(struct msdosfsmount *pmp,   /* so we know the maj/min number */
        fc_purge(ldep, 0);      /* init the fat cache for this denode */
 
        /*
-        * Lock the denode so that it can't be accessed until we've read
-        * it in and have done what we need to it.  Do this here instead
-        * of at the start of msdosfs_hashins() so that reinsert() can
-        * call msdosfs_hashins() with a locked denode.
+        * Insert the denode into the hash queue.  If a collision occurs
+        * throw away the vnode and try again.
         */
-       if (lockmgr(&ldep->de_lock, LK_EXCLUSIVE, NULL, td))
-               panic("deget: unexpected lock failure");
-
-       /*
-        * Insert the denode into the hash queue.
-        */
-       msdosfs_hashins(ldep);
-
+       if (msdosfs_hashins(ldep) != 0) {
+               printf("debug: msdosfs: hashins collision, retrying\n");
+               vput(nvp);
+               free(ldep, M_MSDOSFSNODE);
+               goto again;
+       }
+       nvp->v_data = ldep;
        ldep->de_pmp = pmp;
        ldep->de_refcnt = 1;
        /*
@@ -617,27 +651,6 @@ deextend(struct denode *dep, u_long length)
        return (deupdat(dep, 1));
 }
 
-/*
- * Move a denode to its correct hash queue after the file it represents has
- * been moved to a new directory.
- */
-void
-reinsert(struct denode *dep)
-{
-       /*
-        * Fix up the denode cache.  If the denode is for a directory,
-        * there is nothing to do since the hash is based on the starting
-        * cluster of the directory file and that hasn't changed.  If for a
-        * file the hash is based on the location of the directory entry,
-        * so we must remove it from the cache and re-enter it with the
-        * hash based on the new location of the directory entry.
-        */
-       if (dep->de_Attributes & ATTR_DIRECTORY)
-               return;
-       msdosfs_hashrem(dep);
-       msdosfs_hashins(dep);
-}
-
 /*
  * msdosfs_reclaim(struct vnode *a_vp)
  */
@@ -649,29 +662,25 @@ msdosfs_reclaim(struct vop_reclaim_args *ap)
 
 #ifdef MSDOSFS_DEBUG
        printf("msdosfs_reclaim(): dep %p, file %s, refcnt %ld\n",
-           dep, dep->de_Name, dep->de_refcnt);
+           dep, dep ? dep->de_Name : "?", dep ? dep->de_refcnt : -1);
 #endif
 
        if (prtactive && vp->v_usecount != 0)
                vprint("msdosfs_reclaim(): pushing active", vp);
        /*
-        * Remove the denode from its hash chain.
-        */
-       msdosfs_hashrem(dep);
-       /*
-        * Purge old data structures associated with the denode.
+        * Remove the denode from its hash chain and purge namecache
+        * data associated with the vnode.
         */
        cache_purge(vp);
-       if (dep->de_devvp) {
-               vrele(dep->de_devvp);
-               dep->de_devvp = 0;
-       }
-#if 0 /* XXX */
-       dep->de_flag = 0;
-#endif
-       FREE(dep, M_MSDOSFSNODE);
        vp->v_data = NULL;
-
+       if (dep) {
+               msdosfs_hashrem(dep);
+               if (dep->de_devvp) {
+                       vrele(dep->de_devvp);
+                       dep->de_devvp = 0;
+               }
+               free(dep, M_MSDOSFSNODE);
+       }
        return (0);
 }
 
index bf77ac7..4bcbe78 100644 (file)
@@ -1,5 +1,5 @@
 /* $FreeBSD: src/sys/msdosfs/msdosfs_vnops.c,v 1.95.2.4 2003/06/13 15:05:47 trhodes Exp $ */
-/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vnops.c,v 1.17 2004/08/17 18:57:34 dillon Exp $ */
+/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vnops.c,v 1.18 2004/08/28 19:02:18 dillon Exp $ */
 /*     $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $   */
 
 /*-
@@ -1178,6 +1178,9 @@ abortit:
                        VOP_UNLOCK(fdvp, NULL, 0, td);
                xp = NULL;
        } else {
+               u_long new_dirclust;
+               u_long new_diroffset;
+
                vrele(fvp);
                xp = NULL;
 
@@ -1213,7 +1216,7 @@ abortit:
                }
                if (!doingdirectory) {
                        error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
-                                      &ip->de_dirclust, 0);
+                                      &new_dirclust, 0);
                        if (error) {
                                /* XXX should really panic here, fs is corrupt */
                                if (newparent)
@@ -1221,12 +1224,12 @@ abortit:
                                VOP_UNLOCK(fvp, NULL, 0, td);
                                goto bad;
                        }
-                       if (ip->de_dirclust == MSDOSFSROOT)
-                               ip->de_diroffset = to_diroffset;
+                       if (new_dirclust == MSDOSFSROOT)
+                               new_diroffset = to_diroffset;
                        else
-                               ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
+                               new_diroffset = to_diroffset & pmp->pm_crbomask;
+                       msdosfs_reinsert(ip, new_dirclust, new_diroffset);
                }
-               reinsert(ip);
                if (newparent)
                        VOP_UNLOCK(fdvp, NULL, 0, td);
        }
@@ -1833,7 +1836,7 @@ msdosfs_print(struct vop_print_args *ap)
            "tag VT_MSDOSFS, startcluster %lu, dircluster %lu, diroffset %lu ",
               dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
        printf(" dev %d, %d", major(dep->de_dev), minor(dep->de_dev));
-       lockmgr_printinfo(&dep->de_lock);
+       lockmgr_printinfo(&ap->a_vp->v_lock);
        printf("\n");
        return (0);
 }
index dc006c5..1496bd8 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_node.c  8.6 (Berkeley) 5/22/95
  * $FreeBSD: src/sys/nfs/nfs_node.c,v 1.36.2.3 2002/01/05 22:25:04 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_node.c,v 1.12 2004/08/17 18:57:34 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_node.c,v 1.13 2004/08/28 19:02:20 dillon Exp $
  */
 
 
@@ -137,7 +137,8 @@ loop:
         */
        np = zalloc(nfsnode_zone);
                
-       error = getnewvnode(VT_NFS, mntp, mntp->mnt_vn_ops, &nvp);
+       error = getnewvnode(VT_NFS, mntp, mntp->mnt_vn_ops, &nvp,
+                               0, LK_NOPAUSE);
        if (error) {
                if (nfs_node_hash_lock < 0)
                        wakeup(&nfs_node_hash_lock);
@@ -172,7 +173,6 @@ loop:
        bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
        np->n_fhsize = fhsize;
        lockinit(&np->n_rslock, rsflags, "nfrslk", 0, LK_NOPAUSE);
-       lockinit(&np->n_lock, 0, "nfsnlk", 0, LK_NOPAUSE);
        *npp = np;
 
        if (nfs_node_hash_lock < 0)
@@ -286,8 +286,8 @@ nfs_reclaim(struct vop_reclaim_args *ap)
        }
 
        cache_purge(vp);
-       zfree(nfsnode_zone, vp->v_data);
-       vp->v_data = (void *)0;
+       vp->v_data = NULL;
+       zfree(nfsnode_zone, np);
        return (0);
 }
 
index b134f65..2c24301 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
  * $FreeBSD: src/sys/nfs/nfs_vnops.c,v 1.150.2.5 2001/12/20 19:56:28 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.27 2004/08/17 18:57:34 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.28 2004/08/28 19:02:20 dillon Exp $
  */
 
 
@@ -154,7 +154,7 @@ struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
        { &vop_islocked_desc,           (void *) vop_stdislocked },
        { &vop_lease_desc,              vop_null },
        { &vop_link_desc,               (void *) nfs_link },
-       { &vop_lock_desc,               (void *) vop_sharedlock },
+       { &vop_lock_desc,               (void *) vop_stdlock },
        { &vop_lookup_desc,             (void *) nfs_lookup },
        { &vop_mkdir_desc,              (void *) nfs_mkdir },
        { &vop_mknod_desc,              (void *) nfs_mknod },
@@ -188,7 +188,7 @@ struct vnodeopv_entry_desc nfsv2_specop_entries[] = {
        { &vop_getattr_desc,            (void *) nfs_getattr },
        { &vop_inactive_desc,           (void *) nfs_inactive },
        { &vop_islocked_desc,           (void *) vop_stdislocked },
-       { &vop_lock_desc,               (void *) vop_sharedlock },
+       { &vop_lock_desc,               (void *) vop_stdlock },
        { &vop_print_desc,              (void *) nfs_print },
        { &vop_read_desc,               (void *) nfsspec_read },
        { &vop_reclaim_desc,            (void *) nfs_reclaim },
@@ -206,7 +206,7 @@ struct vnodeopv_entry_desc nfsv2_fifoop_entries[] = {
        { &vop_getattr_desc,            (void *) nfs_getattr },
        { &vop_inactive_desc,           (void *) nfs_inactive },
        { &vop_islocked_desc,           (void *) vop_stdislocked },
-       { &vop_lock_desc,               (void *) vop_sharedlock },
+       { &vop_lock_desc,               (void *) vop_stdlock },
        { &vop_print_desc,              (void *) nfs_print },
        { &vop_read_desc,               (void *) nfsfifo_read },
        { &vop_reclaim_desc,            (void *) nfs_reclaim },
index a582516..d056ec3 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfsnode.h   8.9 (Berkeley) 5/14/95
  * $FreeBSD: /repoman/r/ncvs/src/sys/nfsclient/nfsnode.h,v 1.43 2004/04/14 23:23:55 peadar Exp $
- * $DragonFly: src/sys/vfs/nfs/nfsnode.h,v 1.11 2004/08/17 18:57:34 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfsnode.h,v 1.12 2004/08/28 19:02:20 dillon Exp $
  */
 
 
@@ -92,7 +92,6 @@ struct nfsdmap {
  * Validating ucreds are stored in nfsnode to pass on to NFS read/write RPCs.
  */
 struct nfsnode {
-       struct lock             n_lock;
        LIST_ENTRY(nfsnode)     n_hash;         /* Hash chain */
        CIRCLEQ_ENTRY(nfsnode)  n_timer;        /* Nqnfs timer chain */
        u_quad_t                n_size;         /* Current size of file */
index 5070c59..1fcc713 100644 (file)
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/ntfs/ntfs_inode.h,v 1.6 1999/12/03 20:37:39 semenu Exp $
- * $DragonFly: src/sys/vfs/ntfs/ntfs_inode.h,v 1.4 2004/02/05 21:03:37 rob Exp $
+ * $DragonFly: src/sys/vfs/ntfs/ntfs_inode.h,v 1.5 2004/08/28 19:02:21 dillon Exp $
  */
 
 /* These flags are kept in i_flag. */
@@ -85,10 +85,6 @@ struct ntnode {
 #define        FN_VALID        0x0002
 #define        FN_AATTRNAME    0x0004  /* space allocated for f_attrname */
 struct fnode {
-#ifdef __DragonFly__
-       struct lock     f_lock; /* fnode lock >Keep this first< */
-#endif
-       
        LIST_ENTRY(fnode) f_fnlist;
        struct vnode   *f_vp;           /* Associatied vnode */
        struct ntnode  *f_ip;           /* Associated ntnode */
index 053fc09..fef91b9 100644 (file)
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/ntfs/ntfs_vfsops.c,v 1.20.2.5 2001/12/25 01:44:45 dillon Exp $
- * $DragonFly: src/sys/vfs/ntfs/ntfs_vfsops.c,v 1.20 2004/08/19 00:30:07 dillon Exp $
+ * $DragonFly: src/sys/vfs/ntfs/ntfs_vfsops.c,v 1.21 2004/08/28 19:02:21 dillon Exp $
  */
 
 
@@ -918,7 +918,9 @@ ntfs_vgetex(struct mount *mp, ino_t ino, u_int32_t attrtype, char *attrname,
                return (0);
        }
 
-       error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, ntmp->ntm_mountp->mnt_vn_ops, &vp);
+       error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, 
+                           ntmp->ntm_mountp->mnt_vn_ops, &vp,
+                           VLKTIMEOUT, 0);
        if(error) {
                ntfs_frele(fp);
                ntfs_ntput(ip);
@@ -926,9 +928,6 @@ ntfs_vgetex(struct mount *mp, ino_t ino, u_int32_t attrtype, char *attrname,
        }
        dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino));
 
-#ifdef __DragonFly__
-       lockinit(&fp->f_lock, 0, "fnode", VLKTIMEOUT, 0);
-#endif
        fp->f_vp = vp;
        vp->v_data = fp;
        vp->v_type = f_type;
index 3cc505c..59e97dd 100644 (file)
@@ -36,7 +36,7 @@
  *     @(#)null.h      8.3 (Berkeley) 8/20/94
  *
  * $FreeBSD: src/sys/miscfs/nullfs/null.h,v 1.11.2.3 2001/06/26 04:20:09 bp Exp $
- * $DragonFly: src/sys/vfs/nullfs/null.h,v 1.5 2004/08/17 18:57:34 dillon Exp $
+ * $DragonFly: src/sys/vfs/nullfs/null.h,v 1.6 2004/08/28 19:02:23 dillon Exp $
  */
 
 struct null_args {
@@ -53,9 +53,7 @@ struct null_mount {
  * A cache of vnode references
  */
 struct null_node {
-       struct lock             null_lock;      /* Lock for this vnode. MBF */
-       struct lock             *null_vnlock;   /* lock of lower vnode in the stack */
-       LIST_ENTRY(null_node)   null_hash;      /* Hash list */
+       struct null_node        *null_next;     /* Hash list */
        struct vnode            *null_lowervp;  /* vrefed once */
        struct vnode            *null_vnode;    /* Back pointer */
 };
@@ -66,6 +64,8 @@ struct null_node {
 
 int nullfs_init(struct vfsconf *vfsp);
 int nullfs_uninit(struct vfsconf *vfsp);
+int null_node_add(struct null_node *np);
+void null_node_rem(struct null_node *np);
 int null_node_create(struct mount *mp, struct vnode *target, struct vnode **vpp);
 int null_bypass(struct vop_generic_args *ap);
 
@@ -76,8 +76,6 @@ struct vnode *null_checkvp(struct vnode *vp, char *fil, int lno);
 #define        NULLVPTOLOWERVP(vp) (VTONULL(vp)->null_lowervp)
 #endif
 
-extern struct lock null_hashlock;
-
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_NULLFSNODE);
 #endif
index be18768..2ffe8e4 100644 (file)
@@ -36,7 +36,7 @@
  *     @(#)null_subr.c 8.7 (Berkeley) 5/14/95
  *
  * $FreeBSD: src/sys/miscfs/nullfs/null_subr.c,v 1.21.2.4 2001/06/26 04:20:09 bp Exp $
- * $DragonFly: src/sys/vfs/nullfs/Attic/null_subr.c,v 1.12 2004/08/17 18:57:34 dillon Exp $
+ * $DragonFly: src/sys/vfs/nullfs/Attic/null_subr.c,v 1.13 2004/08/28 19:02:23 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -49,7 +49,6 @@
 #include "null.h"
 
 #define LOG2_SIZEVNODE 7               /* log2(sizeof struct vnode) */
-#define        NNULLNODECACHE 16
 
 /*
  * Null layer cache:
@@ -62,9 +61,9 @@
 #define        NULL_NHASH(vp) \
        (&null_node_hashtbl[(((uintptr_t)vp)>>LOG2_SIZEVNODE) & null_node_hash])
 
-static LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
+static struct null_node **null_node_hashtbl;
 static u_long null_node_hash;
-struct lock null_hashlock;
+static struct lwkt_token null_ihash_token;
 
 static MALLOC_DEFINE(M_NULLFSHASH, "NULLFS hash", "NULLFS hash table");
 MALLOC_DEFINE(M_NULLFSNODE, "NULLFS node", "NULLFS vnode private part");
@@ -81,8 +80,13 @@ int
 nullfs_init(struct vfsconf *vfsp)
 {
        NULLFSDEBUG("nullfs_init\n");           /* printed during system boot */
-       null_node_hashtbl = hashinit(NNULLNODECACHE, M_NULLFSHASH, &null_node_hash);
-       lockinit(&null_hashlock, 0, "nullhs", 0, 0);
+       null_node_hash = 16;
+       while (null_node_hash < desiredvnodes)
+               null_node_hash <<= 1;
+       null_node_hashtbl = malloc(sizeof(void *) * null_node_hash,
+                                   M_NULLFSHASH, M_WAITOK|M_ZERO);
+       --null_node_hash;
+       lwkt_token_init(&null_ihash_token);
        return (0);
 }
 
@@ -91,141 +95,197 @@ nullfs_uninit(struct vfsconf *vfsp)
 {
         if (null_node_hashtbl) {
                free(null_node_hashtbl, M_NULLFSHASH);
+               null_node_hashtbl = NULL;
        }
        return (0);
 }
 
 /*
  * Return a vref'ed alias for lower vnode if already exists, else 0.
- * Lower vnode should be locked on entry and will be left locked on exit.
+ * Lower vnode should be locked (but with no additional refs) on entry
+ * and will be unlocked on return if the search was successful, and left
+ * locked if the search was not successful.
  */
 static struct vnode *
 null_node_find(struct mount *mp, struct vnode *lowervp)
 {
        struct thread *td = curthread;  /* XXX */
-       struct null_node_hashhead *hd;
-       struct null_node *a;
+       struct null_node *np;
+       struct null_node *xp;
        struct vnode *vp;
+       lwkt_tokref ilock;
 
-       /*
-        * Find hash base, and then search the (two-way) linked
-        * list looking for a null_node structure which is referencing
-        * the lower vnode.  If found, the increment the null_node
-        * reference count (but NOT the lower vnode's vref counter).
-        */
-       hd = NULL_NHASH(lowervp);
+       lwkt_gettoken(&ilock, &null_ihash_token);
 loop:
-       lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, td);
-       LIST_FOREACH(a, hd, null_hash) {
-               if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
-                       vp = NULLTOV(a);
-                       lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
-                       /*
-                        * We need vget for the VXLOCK
-                        * stuff, but we don't want to lock
-                        * the lower node.
-                        */
+       for (np = *NULL_NHASH(lowervp); np; np = np->null_next) {
+               if (np->null_lowervp == lowervp && NULLTOV(np)->v_mount == mp) {
+                       vp = NULLTOV(np);
                        if (vget(vp, NULL, LK_EXCLUSIVE | LK_CANRECURSE, td)) {
                                printf ("null_node_find: vget failed.\n");
                                goto loop;
                        }
+
+                       /*
+                        * vget() might have blocked, we have to check that
+                        * our vnode is still valid.
+                        */
+                       xp = *NULL_NHASH(lowervp);
+                       while (xp) {
+                               if (xp == np && xp->null_lowervp == lowervp &&
+                                   NULLTOV(xp) == vp &&
+                                   NULLTOV(xp)->v_mount == mp) {
+                                       break;
+                               }
+                               xp = xp->null_next;
+                       }
+                       if (xp == NULL) {
+                               printf ("null_node_find: node race, retry.\n");
+                               vput(vp);
+                               goto loop;
+                       }
+                       /*
+                        * SUCCESS!  Returned the locked and referenced vp
+                        * and release the lock on lowervp.
+                        */
                        VOP_UNLOCK(lowervp, NULL, 0, td);
+                       lwkt_reltoken(&ilock);
                        return (vp);
                }
        }
-       lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
 
-       return NULLVP;
+       /*
+        * Failure, leave lowervp locked on return.
+        */
+       lwkt_reltoken(&ilock);
+       return(NULL);
 }
 
+int
+null_node_add(struct null_node *np)
+{
+       struct null_node **npp;
+       struct null_node *n2;
+       lwkt_tokref ilock;
+
+       lwkt_gettoken(&ilock, &null_ihash_token);
+       npp = NULL_NHASH(np->null_lowervp);
+       while ((n2 = *npp) != NULL) {
+               if (n2->null_lowervp == np->null_lowervp) {
+                       lwkt_reltoken(&ilock);
+                       return(EBUSY);
+               }
+               npp = &n2->null_next;
+       }
+       np->null_next = NULL;
+       *npp = np;
+       lwkt_reltoken(&ilock);
+       return(0);
+}
+
+void
+null_node_rem(struct null_node *np)
+{
+       struct null_node **npp;
+       struct null_node *n2;
+       lwkt_tokref ilock;
+
+       lwkt_gettoken(&ilock, &null_ihash_token);
+       npp = NULL_NHASH(np->null_lowervp);
+       while ((n2 = *npp) != NULL) {
+               if (n2 == np)
+                       break;
+               npp = &n2->null_next;
+       }
+       KKASSERT(np == n2);
+       *npp = np->null_next;
+       np->null_next = NULL;
+       lwkt_reltoken(&ilock);
+}
 
 /*
- * Make a new null_node node.
- * Vp is the alias vnode, lofsvp is the lower vnode.
- * Maintain a reference to (lowervp).
+ * Make a new null_node node.  vp is the null mount vnode, lowervp is the
+ * lower vnode.  Maintain a reference to (lowervp).  lowervp must be
+ * locked on call.
  */
 static int
 null_node_alloc(struct mount *mp, struct vnode *lowervp, struct vnode **vpp)
 {
-       struct thread *td = curthread;  /* XXX */
-       struct null_node_hashhead *hd;
-       struct null_node *xp;
-       struct vnode *othervp, *vp;
+       struct null_node *np;
+       struct thread *td;
+       struct vnode *vp;
        int error;
 
+       td = curthread;
+retry:
+       /*
+        * If we have already hashed the vp we can just return it.
+        */
+       *vpp = null_node_find(mp, lowervp);
+       if (*vpp)
+               return 0;
+
        /*
-        * Do the MALLOC before the getnewvnode since doing so afterward
-        * might cause a bogus v_data pointer to get dereferenced
-        * elsewhere if MALLOC should block.
+        * lowervp is locked but not referenced at this point.
         */
-       MALLOC(xp, struct null_node *, sizeof(struct null_node),
-           M_NULLFSNODE, M_WAITOK);
+       MALLOC(np, struct null_node *, sizeof(struct null_node),
+              M_NULLFSNODE, M_WAITOK);
 
-       error = getnewvnode(VT_NULL, mp, mp->mnt_vn_ops, vpp);
+       error = getnewvnode(VT_NULL, mp, mp->mnt_vn_ops, vpp, 0, LK_CANRECURSE);
        if (error) {
-               FREE(xp, M_NULLFSNODE);
+               FREE(np, M_NULLFSNODE);
                return (error);
        }
        vp = *vpp;
 
-       vp->v_type = lowervp->v_type;
-
        /*
+        * Set up the np/vp relationship and set the lower vnode.
+        *
         * XXX:
         * When nullfs encounters sockets or device nodes, it
-        * has a hard time working with the normal vp union.
-        * This still needs to be investigated.
+        * has a hard time working with the normal vp union, probably
+        * because the device has not yet been opened.  Needs investigation.
         */
+       vp->v_type = lowervp->v_type;
        if (vp->v_type == VCHR || vp->v_type == VBLK)
                addaliasu(vp, lowervp->v_udev);
        else
-               vp->v_un = lowervp->v_un;
-       lockinit(&xp->null_lock, 0, "nullnode", 0, LK_CANRECURSE);
-       xp->null_vnode = vp;
-       vp->v_data = xp;
-       xp->null_lowervp = lowervp;
-       /*
-        * Before we insert our new node onto the hash chains,
-        * check to see if someone else has beaten us to it.
-        * (We could have slept in MALLOC.)
-        */
-       othervp = null_node_find(mp, lowervp);
-       if (othervp) {
-               vp->v_data = NULL;
-               FREE(xp, M_NULLFSNODE);
-               vp->v_type = VBAD;      /* node is discarded */
-               vrele(vp);
-               *vpp = othervp;
-               return 0;
-       }
+               vp->v_un = lowervp->v_un;       /* XXX why this assignment? */
+       np->null_vnode = vp;
+       np->null_lowervp = lowervp;
 
        /*
-        * From NetBSD:
-        * Now lock the new node. We rely on the fact that we were passed
-        * a locked vnode. If the lower node is exporting a struct lock
-        * (v_vnlock != NULL) then we just set the upper v_vnlock to the
-        * lower one, and both are now locked. If the lower node is exporting
-        * NULL, then we copy that up and manually lock the new vnode.
+        * Lock our new vnode
         */
-
-       lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, td);
-       vp->v_vnlock = lowervp->v_vnlock;
        error = VOP_LOCK(vp, NULL, LK_EXCLUSIVE | LK_THISLAYER, td);
        if (error)
                panic("null_node_alloc: can't lock new vnode\n");
 
+       /*
+        * Try to add our new node to the hash table.  If a collision
+        * occurs someone else beat us to it and we need to destroy the
+        * vnode and retry.
+        */
+       if (null_node_add(np) != 0) {
+               free(np, M_NULLFSNODE);
+               vput(vp);
+               goto retry;
+       }
+
+       /*
+        * Finish up.  Link the vnode and null_node together, ref lowervp
+        * for the null node.  lowervp is already locked so the lock state
+        * is already properly synchronized.
+        */
+       vp->v_data = np;
        vref(lowervp);
-       hd = NULL_NHASH(lowervp);
-       LIST_INSERT_HEAD(hd, xp, null_hash);
-       lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
-       return 0;
+       return (0);
 }
 
 
 /*
  * Try to find an existing null_node vnode refering to the given underlying
- * vnode (which should be locked). If no vnode found, create a new null_node
- * vnode which contains a reference to the lower vnode.
+ * vnode (which should be locked and referenced). If no vnode found, create
+ * a new null_node vnode which contains a reference to the lower vnode.
  */
 int
 null_node_create(struct mount *mp, struct vnode *lowervp, struct vnode **newvpp)
@@ -235,8 +295,8 @@ null_node_create(struct mount *mp, struct vnode *lowervp, struct vnode **newvpp)
        aliasvp = null_node_find(mp, lowervp);
        if (aliasvp) {
                /*
-                * null_node_find has taken another reference
-                * to the alias vnode.
+                * null_node_find() has unlocked lowervp for us, so we just
+                * have to get rid of the reference.
                 */
                vrele(lowervp);
 #ifdef NULLFS_DEBUG
@@ -246,7 +306,8 @@ null_node_create(struct mount *mp, struct vnode *lowervp, struct vnode **newvpp)
                int error;
 
                /*
-                * Get new vnode.
+                * Get new vnode.  Note that lowervp is locked and referenced
+                * at this point (as it was passed to us).
                 */
                NULLFSDEBUG("null_node_create: create new alias vnode\n");
 
@@ -258,7 +319,7 @@ null_node_create(struct mount *mp, struct vnode *lowervp, struct vnode **newvpp)
                        return error;
 
                /*
-                * aliasvp is already vref'd by getnewvnode()
+                * aliasvp is already locked and ref'd by getnewvnode()
                 */
        }
 
index 96d262c..8e32c35 100644 (file)
@@ -38,7 +38,7 @@
  * Ancestors:
  *     @(#)lofs_vnops.c        1.2 (Berkeley) 6/18/92
  * $FreeBSD: src/sys/miscfs/nullfs/null_vnops.c,v 1.38.2.6 2002/07/31 00:32:28 semenu Exp $
- * $DragonFly: src/sys/vfs/nullfs/null_vnops.c,v 1.13 2004/08/17 18:57:34 dillon Exp $
+ * $DragonFly: src/sys/vfs/nullfs/null_vnops.c,v 1.14 2004/08/28 19:02:23 dillon Exp $
  *     ...and...
  *     @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
  *
@@ -236,13 +236,13 @@ static int        null_unlock(struct vop_unlock_args *ap);
 int
 null_bypass(struct vop_generic_args *ap)
 {
-       register struct vnode **this_vp_p;
+       struct vnode **this_vp_p;
        int error;
        struct vnode *old_vps[VDESC_MAX_VPS];
        struct vnode **vps_p[VDESC_MAX_VPS];
        struct vnode ***vppp;
        struct vnodeop_desc *descp = ap->a_desc;
-       int reles, i;
+       int reles, i, j;
 
        if (null_bug_bypass)
                printf ("null_bypass: %s\n", descp->vdesc_name);
@@ -258,11 +258,9 @@ null_bypass(struct vop_generic_args *ap)
 
        /*
         * Map the vnodes going in.
-        * Later, we'll invoke the operation based on
-        * the first mapped vnode's operation vector.
         */
        reles = descp->vdesc_flags;
-       for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
+       for (i = 0; i < VDESC_MAX_VPS; ++i) {
                if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
                        break;   /* bail out at end of list */
                vps_p[i] = this_vp_p =
@@ -277,13 +275,13 @@ null_bypass(struct vop_generic_args *ap)
                        old_vps[i] = NULLVP;
                } else {
                        old_vps[i] = *this_vp_p;
-                       *(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
+                       *this_vp_p = NULLVPTOLOWERVP(*this_vp_p);
                        /*
-                        * XXX - Several operations have the side effect
-                        * of vrele'ing their vp's.  We must account for
-                        * that.  (This should go away in the future.)
+                        * Several operations have the side effect of vrele'ing
+                        * their vp's.  We must account for that in the lower
+                        * vp we pass down.
                         */
-                       if (reles & VDESC_VP0_WILLRELE)
+                       if (reles & (VDESC_VP0_WILLRELE << i))
                                vref(*this_vp_p);
                }
 
@@ -303,22 +301,43 @@ null_bypass(struct vop_generic_args *ap)
        }
 
        /*
-        * Maintain the illusion of call-by-value
-        * by restoring vnodes in the argument structure
-        * to their original value.
+        * Maintain the illusion of call-by-value by restoring vnodes in the
+        * argument structure to their original value.
         */
        reles = descp->vdesc_flags;
-       for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
+       for (i = 0; i < VDESC_MAX_VPS; ++i) {
                if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
                        break;   /* bail out at end of list */
                if (old_vps[i]) {
                        *(vps_p[i]) = old_vps[i];
-#if 0
-                       if (reles & VDESC_VP0_WILLUNLOCK)
-                               VOP_UNLOCK(*(vps_p[i]), NULL, LK_THISLAYER, curproc);
-#endif
-                       if (reles & VDESC_VP0_WILLRELE)
-                               vrele(*(vps_p[i]));
+
+                       /*
+                        * Since we operated on the lowervp's instead of the
+                        * null node vp's, we have to adjust the null node
+                        * vp's based on what the VOP did to the lower vp.
+                        * 
+                        * Note: the unlock case only occurs with rename.
+                        * tdvp and tvp are both locked on call and must be
+                        * unlocked on return.
+                        *
+                        * Unlock semantics indicate that if two locked vp's
+                        * are passed and they are the same vp, they are only
+                        * actually locked once.
+                        */
+                       if (reles & (VDESC_VP0_WILLUNLOCK << i)) {
+                               VOP_UNLOCK(old_vps[i], NULL,
+                                           LK_THISLAYER, curthread);
+                               for (j = i + 1; j < VDESC_MAX_VPS; ++j) {
+                                       if (descp->vdesc_vp_offsets[j] == VDESC_NO_OFFSET)
+                                               break;
+                                       if (old_vps[i] == old_vps[j]) {
+                                               reles &= ~(1 << (VDESC_VP0_WILLUNLOCK << j));
+                                       }
+                               }
+                       }
+
+                       if (reles & (VDESC_VP0_WILLRELE << i))
+                               vrele(old_vps[i]);
                }
        }
 
@@ -366,27 +385,39 @@ null_lookup(struct vop_lookup_args *ap)
        struct vnode *vp, *ldvp, *lvp;
        int error;
 
-       if ((flags & CNP_ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
-           (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME))
+       if ((flags & CNP_ISLASTCN) && 
+           (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+           (cnp->cn_nameiop == NAMEI_DELETE || 
+            cnp->cn_nameiop == NAMEI_RENAME)) {
                return (EROFS);
+       }
+       ldvp = NULLVPTOLOWERVP(dvp);
+
        /*
-        * Although it is possible to call null_bypass(), we'll do
-        * a direct call to reduce overhead
+        * If we are doing a ".." lookup we must release the lock on dvp
+        * now, before we run a lookup in the underlying fs, or we may 
+        * deadlock.  If we do this we must protect ldvp by ref'ing it.
+        */
+       if (flags & CNP_ISDOTDOT) {
+               vref(ldvp);
+               VOP_UNLOCK(dvp, NULL, LK_THISLAYER, td);
+       }
+
+       /*
+        * Due to the non-deterministic nature of the handling of the
+        * parent directory lock by lookup, we cannot call null_bypass()
+        * here.  We must make a direct call.  It's faster to do a direct
+        * call, anyway.
         */
-       ldvp = NULLVPTOLOWERVP(dvp);
        vp = lvp = NULL;
        error = VOP_LOOKUP(ldvp, NCPNULL, &lvp, NCPPNULL, cnp);
        if (error == EJUSTRETURN && (flags & CNP_ISLASTCN) &&
            (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
-           (cnp->cn_nameiop == NAMEI_CREATE || cnp->cn_nameiop == NAMEI_RENAME))
+           (cnp->cn_nameiop == NAMEI_CREATE || 
+            cnp->cn_nameiop == NAMEI_RENAME)) {
                error = EROFS;
+       }
 
-       /*
-        * Rely only on the PDIRUNLOCK flag which should be carefully
-        * tracked by underlying filesystem.
-        */
-       if (cnp->cn_flags & CNP_PDIRUNLOCK)
-               VOP_UNLOCK(dvp, NULL, LK_THISLAYER, td);
        if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) {
                if (ldvp == lvp) {
                        *ap->a_vpp = dvp;
@@ -398,6 +429,20 @@ null_lookup(struct vop_lookup_args *ap)
                                *ap->a_vpp = vp;
                }
        }
+
+       /*
+        * The underlying fs will set PDIRUNLOCK if it unlocked the parent
+        * directory, which means we have to follow suit in the nullfs layer.
+        * Note that the parent directory may have already been unlocked due
+        * to the ".." case.  Note that use of cnp->cn_flags instead of flags.
+        */
+       if (flags & CNP_ISDOTDOT) {
+               if ((cnp->cn_flags & CNP_PDIRUNLOCK) == 0)
+                       VOP_LOCK(dvp, NULL, LK_THISLAYER | LK_EXCLUSIVE, td);
+               vrele(ldvp);
+       } else if (cnp->cn_flags & CNP_PDIRUNLOCK) {
+               VOP_UNLOCK(dvp, NULL, LK_THISLAYER, td);
+       }
        return (error);
 }
 
@@ -549,9 +594,9 @@ null_rename(struct vop_rename_args *ap)
 }
 
 /*
- * We need to process our own vnode lock and then clear the
- * interlock flag as it applies only to our vnode, not the
- * vnodes below us on the stack.
+ * A special flag, LK_THISLAYER, causes the locking function to operate
+ * ONLY on the nullfs layer.  Otherwise we are responsible for locking not
+ * only our layer, but the lower layer as well.
  *
  * null_lock(struct vnode *a_vp, lwkt_tokref_t a_vlock, int a_flags,
  *          struct thread *a_td)
@@ -565,67 +610,51 @@ null_lock(struct vop_lock_args *ap)
        struct vnode *lvp;
        int error;
 
-       if (flags & LK_THISLAYER) {
-               if (vp->v_vnlock != NULL) {
-                       /* lock is shared across layers */
-                       if (flags & LK_INTERLOCK)
-                               lwkt_reltoken(ap->a_vlock);
-                       return 0;
-               }
-               error = lockmgr(&np->null_lock, flags & ~LK_THISLAYER,
-                   ap->a_vlock, ap->a_td);
+       /*
+        * Lock the nullfs layer first, disposing of the interlock in the
+        * process.
+        */
+       error = lockmgr(&vp->v_lock, flags & ~LK_THISLAYER,
+                       ap->a_vlock, ap->a_td);
+       flags &= ~LK_INTERLOCK;
+
+       /*
+        * If locking only the nullfs layer, or if there is no lower layer,
+        * or if an error occured while attempting to lock the nullfs layer,
+        * we are done.
+        */
+       if ((flags & LK_THISLAYER) || np->null_lowervp == NULL || error)
                return (error);
-       }
 
-       if (vp->v_vnlock != NULL) {
-               /*
-                * The lower level has exported a struct lock to us. Use
-                * it so that all vnodes in the stack lock and unlock
-                * simultaneously. Note: we don't DRAIN the lock as DRAIN
-                * decommissions the lock - just because our vnode is
-                * going away doesn't mean the struct lock below us is.
-                * LK_EXCLUSIVE is fine.
-                */
-               if ((flags & LK_TYPE_MASK) == LK_DRAIN) {
-                       NULLFSDEBUG("null_lock: avoiding LK_DRAIN\n");
-                       return(lockmgr(vp->v_vnlock,
+       /*
+        * Lock the underlying vnode.  If we are draining we should not drain
+        * the underlying vnode, since it is not being destroyed, but we do
+        * lock it exclusively in that case.  Note that any interlocks have
+        * already been disposed of above.
+        */
+       lvp = np->null_lowervp;
+       if ((flags & LK_TYPE_MASK) == LK_DRAIN) {
+               NULLFSDEBUG("null_lock: avoiding LK_DRAIN\n");
+               error = vn_lock(lvp, NULL,
                                (flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE,
-                               ap->a_vlock, ap->a_td));
-               }
-               return(lockmgr(vp->v_vnlock, flags, ap->a_vlock, ap->a_td));
+                               ap->a_td);
+       } else {
+               error = vn_lock(lvp, NULL, flags, ap->a_td);
        }
+
        /*
-        * To prevent race conditions involving doing a lookup
-        * on "..", we have to lock the lower node, then lock our
-        * node. Most of the time it won't matter that we lock our
-        * node (as any locking would need the lower one locked
-        * first). But we can LK_DRAIN the upper lock as a step
-        * towards decomissioning it.
+        * If an error occured we have to undo our nullfs lock, then return
+        * the original error.
         */
-       lvp = NULLVPTOLOWERVP(vp);
-       if (lvp == NULL)
-               return (lockmgr(&np->null_lock, flags, ap->a_vlock, ap->a_td));
-       if (flags & LK_INTERLOCK) {
-               VI_UNLOCK(ap->a_vlock, vp);
-               flags &= ~LK_INTERLOCK;
-       }
-       if ((flags & LK_TYPE_MASK) == LK_DRAIN) {
-               error = VOP_LOCK(lvp, ap->a_vlock,
-                       (flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE, ap->a_td);
-       } else
-               error = VOP_LOCK(lvp, ap->a_vlock, flags, ap->a_td);
-       if (error)
-               return (error);
-       error = lockmgr(&np->null_lock, flags, ap->a_vlock, ap->a_td);
        if (error)
-               VOP_UNLOCK(lvp, NULL, 0, ap->a_td);
-       return (error);
+               lockmgr(&vp->v_lock, LK_RELEASE, NULL, ap->a_td);
+       return(error);
 }
 
 /*
- * We need to process our own vnode unlock and then clear the
- * interlock flag as it applies only to our vnode, not the
- * vnodes below us on the stack.
+ * A special flag, LK_THISLAYER, causes the unlocking function to operate
+ * ONLY on the nullfs layer.  Otherwise we are responsible for unlocking not
+ * only our layer, but the lower layer as well.
  *
  * null_unlock(struct vnode *a_vp, lwkt_tokref_t a_vlock, int a_flags,
  *             struct thread *a_td)
@@ -637,41 +666,59 @@ null_unlock(struct vop_unlock_args *ap)
        int flags = ap->a_flags;
        struct null_node *np = VTONULL(vp);
        struct vnode *lvp;
+       int error;
 
-       if (vp->v_vnlock != NULL) {
-               if (flags & LK_THISLAYER)
-                       return 0;       /* the lock is shared across layers */
-               flags &= ~LK_THISLAYER;
-               return (lockmgr(vp->v_vnlock, flags | LK_RELEASE,
-                       ap->a_vlock, ap->a_td));
+       /*
+        * nullfs layer only
+        */
+       if (flags & LK_THISLAYER) {
+               error = lockmgr(&vp->v_lock, 
+                               (flags & ~LK_THISLAYER) | LK_RELEASE,
+                               ap->a_vlock,
+                               ap->a_td);
+               return (error);
        }
-       lvp = NULLVPTOLOWERVP(vp);
-       if (lvp == NULL)
-               return (lockmgr(&np->null_lock, flags | LK_RELEASE, ap->a_vlock, ap->a_td));
-       if ((flags & LK_THISLAYER) == 0) {
-               if (flags & LK_INTERLOCK) {
-                       VI_UNLOCK(ap->a_vlock, vp);
-                       flags &= ~LK_INTERLOCK;
-               }
-               VOP_UNLOCK(lvp, ap->a_vlock, flags, ap->a_td);
-       } else {
-               flags &= ~LK_THISLAYER;
+
+       /*
+        * If there is no underlying vnode the lock operation occurs at
+        * the nullfs layer.
+        */
+       lvp = np->null_lowervp;
+       if (lvp == NULL) {
+               error = lockmgr(&vp->v_lock, flags | LK_RELEASE,
+                               ap->a_vlock, ap->a_td);
+               return(error);
        }
-       ap->a_flags = flags;
-       return (lockmgr(&np->null_lock, flags | LK_RELEASE, ap->a_vlock, ap->a_td));
+
+       /*
+        * Unlock the lower layer first, then our nullfs layer.
+        */
+       VOP_UNLOCK(lvp, NULL, flags & ~LK_INTERLOCK, ap->a_td);
+       error = lockmgr(&vp->v_lock, flags | LK_RELEASE,
+                       ap->a_vlock, ap->a_td);
+       return (error);
 }
 
 /*
  * null_islocked(struct vnode *a_vp, struct thread *a_td)
+ *
+ * If a lower layer exists return the lock status of the lower layer,
+ * otherwise return the lock status of our nullfs layer.
  */
 static int
 null_islocked(struct vop_islocked_args *ap)
 {
        struct vnode *vp = ap->a_vp;
+       struct vnode *lvp;
+       struct null_node *np = VTONULL(vp);
+       int error;
 
-       if (vp->v_vnlock != NULL)
-               return (lockstatus(vp->v_vnlock, ap->a_td));
-       return (lockstatus(&VTONULL(vp)->null_lock, ap->a_td));
+       lvp = np->null_lowervp;
+       if (lvp == NULL)
+               error = lockstatus(&vp->v_lock, ap->a_td);
+       else
+               error = VOP_ISLOCKED(lvp, ap->a_td);
+       return (error);
 }
 
 
@@ -686,27 +733,30 @@ static int
 null_inactive(struct vop_inactive_args *ap)
 {
        struct vnode *vp = ap->a_vp;
-       struct null_node *xp = VTONULL(vp);
-       struct vnode *lowervp = xp->null_lowervp;
-
-       lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, ap->a_td);
-       LIST_REMOVE(xp, null_hash);
-       lockmgr(&null_hashlock, LK_RELEASE, NULL, ap->a_td);
+       struct null_node *np = VTONULL(vp);
+       struct vnode *lowervp;
 
-       xp->null_lowervp = NULLVP;
-       if (vp->v_vnlock != NULL) {
-               vp->v_vnlock = &xp->null_lock;  /* we no longer share the lock */
-       } else {
-               VOP_UNLOCK(vp, NULL, LK_THISLAYER, ap->a_td);
+       /*
+        * Clean out the lowervp.  Due to the drain the lower vp has
+        * been exclusively locked.  We undo that, then release our
+        * null_lowervp reference to lowervp.  The lower vnode's
+        * inactive routine may or may not be called when we do the
+        * final vrele().
+        */
+       if (np) {
+               null_node_rem(np);
+               lowervp = np->null_lowervp;
+               np->null_lowervp = NULLVP;
+               if (lowervp) {
+                       vput(lowervp);
+                       vrele (lowervp);
+               }
        }
 
-       vput(lowervp);
        /*
-        * Now it is safe to drop references to the lower vnode.
-        * VOP_INACTIVE() will be called by vrele() if necessary.
+        * Now it is safe to release our nullfs layer vnode.
         */
-       vrele (lowervp);
-
+       VOP_UNLOCK(vp, NULL, LK_THISLAYER, ap->a_td);
        return (0);
 }
 
@@ -720,11 +770,12 @@ static int
 null_reclaim(struct vop_reclaim_args *ap)
 {
        struct vnode *vp = ap->a_vp;
-       void *vdata = vp->v_data;
+       struct null_node *np;
 
+       np = VTONULL(vp);
        vp->v_data = NULL;
-       FREE(vdata, M_NULLFSNODE);
-
+       if (np)
+               free(np, M_NULLFSNODE);
        return (0);
 }
 
@@ -735,14 +786,19 @@ static int
 null_print(struct vop_print_args *ap)
 {
        struct vnode *vp = ap->a_vp;
+       struct null_node *np = VTONULL(vp);
 
-       printf ("\ttag VT_NULLFS, vp=%p, lowervp=%p\n", vp, NULLVPTOLOWERVP(vp));
-       if (vp->v_vnlock != NULL) {
-               printf("\tvnlock: ");
-               lockmgr_printinfo(vp->v_vnlock);
+       if (np == NULL) {
+               printf ("\ttag VT_NULLFS, vp=%p, NULL v_data!\n", vp);
+               return(0);
+       }
+       printf ("\ttag VT_NULLFS, vp=%p, lowervp=%p\n", vp, np->null_lowervp);
+       if (np->null_lowervp != NULL) {
+               printf("\tlowervp_lock: ");
+               lockmgr_printinfo(&np->null_lowervp->v_lock);
        } else {
                printf("\tnull_lock: ");
-               lockmgr_printinfo(&VTONULL(vp)->null_lock);
+               lockmgr_printinfo(&vp->v_lock);
        }
        printf("\n");
        return (0);
index f67cc93..270794d 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/nwfs/nwfs_node.c,v 1.3.2.8 2001/12/25 01:44:45 dillon Exp $
- * $DragonFly: src/sys/vfs/nwfs/nwfs_node.c,v 1.13 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/nwfs/nwfs_node.c,v 1.14 2004/08/28 19:02:24 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -164,34 +164,34 @@ rescan:
         * elsewhere if MALLOC should block.
         */
        MALLOC(np, struct nwnode *, sizeof *np, M_NWNODE, M_WAITOK | M_ZERO);
-       error = getnewvnode(VT_NWFS, mp, mp->mnt_vn_ops, &vp);
+       error = getnewvnode(VT_NWFS, mp, mp->mnt_vn_ops, &vp, 0, 0);
        if (error) {
                *vpp = NULL;
                FREE(np, M_NWNODE);
                return (error);
        }
-       vp->v_data = np;
        np->n_vnode = vp;
        np->n_mount = nmp;
-       lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, td);
+       lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL, td);
+
        /*
         * Another process can create vnode while we blocked in malloc() or
         * getnewvnode(). Rescan list again.
         */
+       lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, td);
        if (nwfs_hashlookup(nmp, fid, NULL) == 0) {
-               vp->v_data = NULL;
                np->n_vnode = NULL;
-               vrele(vp);
-               FREE(np, M_NWNODE);
+               vput(vp);
+               free(np, M_NWNODE);
                goto rescan;
        }
        *vpp = vp;
+       vp->v_data = np;
        np->n_fid = fid;
        np->n_flag |= NNEW;
        lockinit(&np->n_lock, 0, "nwnode", VLKTIMEOUT, LK_CANRECURSE);
        nhpp = NWNOHASH(fid);
        LIST_INSERT_HEAD(nhpp, np, n_hash);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
        lockmgr(&nwhashlock, LK_RELEASE, NULL, td);
        return 0;
 }
@@ -221,8 +221,8 @@ nwfs_reclaim(struct vop_reclaim_args *ap)
        struct nwmount *nmp = VTONWFS(vp);
        struct thread *td = ap->a_td;
        
-       NCPVNDEBUG("%s,%d\n", np->n_name, vp->v_usecount);
-       if (np->n_refparent) {
+       NCPVNDEBUG("%s,%d\n", (np ? np->n_name : "?"), vp->v_usecount);
+       if (np && np->n_refparent) {
                np->n_refparent = 0;
                if (nwfs_lookupnp(nmp, np->n_parent, td, &dnp) == 0) {
                        dvp = dnp->n_vnode;
@@ -230,18 +230,19 @@ nwfs_reclaim(struct vop_reclaim_args *ap)
                        NCPVNDEBUG("%s: has no parent ?\n",np->n_name);
                }
        }
-       lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, td);
-       LIST_REMOVE(np, n_hash);
-       lockmgr(&nwhashlock, LK_RELEASE, NULL, td);
+       if (np) {
+               lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, td);
+               LIST_REMOVE(np, n_hash);
+               lockmgr(&nwhashlock, LK_RELEASE, NULL, td);
+       }
        cache_purge(vp);
-       if (nmp->n_root == np) {
+       if (nmp->n_root == np)
                nmp->n_root = NULL;
-       }
        vp->v_data = NULL;
-       FREE(np, M_NWNODE);
-       if (dvp) {
+       if (np)
+               free(np, M_NWNODE);
+       if (dvp)
                vrele(dvp);
-       }
        return (0);
 }
 
@@ -261,13 +262,13 @@ nwfs_inactive(struct vop_inactive_args *ap)
        cred = td->td_proc->p_ucred;
 
        NCPVNDEBUG("%s: %d\n", VTONW(vp)->n_name, vp->v_usecount);
-       if (np->opened) {
+       if (np && np->opened) {
                error = nwfs_vinvalbuf(vp, V_SAVE, td, 1);
                error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, td, cred);
                np->opened = 0;
        }
        VOP_UNLOCK(vp, NULL, 0, td);
-       if (np->n_flag & NSHOULDFREE) {
+       if (np == NULL || (np->n_flag & NSHOULDFREE)) {
                cache_purge(vp);
                vgone(vp);
        }
index 6c2a31c..1a802db 100644 (file)
@@ -36,7 +36,7 @@
  *     @(#)portal_vfsops.c     8.11 (Berkeley) 5/14/95
  *
  * $FreeBSD: src/sys/miscfs/portal/portal_vfsops.c,v 1.26.2.2 2001/07/26 20:37:16 iedowse Exp $
- * $DragonFly: src/sys/vfs/portal/portal_vfsops.c,v 1.10 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/portal/portal_vfsops.c,v 1.11 2004/08/28 19:02:25 dillon Exp $
  */
 
 /*
@@ -115,7 +115,7 @@ portal_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp,
         
        vfs_add_vnodeops(&mp->mnt_vn_ops, portal_vnodeop_entries);
 
-       error = getnewvnode(VT_PORTAL, mp, mp->mnt_vn_ops, &rvp); /* XXX */
+       error = getnewvnode(VT_PORTAL, mp, mp->mnt_vn_ops, &rvp, 0, 0);
        if (error) {
                FREE(fmp, M_PORTALFSMNT);
                FREE(pn, M_TEMP);
index c080444..ed6064d 100644 (file)
@@ -36,7 +36,7 @@
  *     @(#)portal_vnops.c      8.14 (Berkeley) 5/21/95
  *
  * $FreeBSD: src/sys/miscfs/portal/portal_vnops.c,v 1.38 1999/12/21 06:29:00 chris Exp $
- * $DragonFly: src/sys/vfs/portal/portal_vnops.c,v 1.15 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/portal/portal_vnops.c,v 1.16 2004/08/28 19:02:25 dillon Exp $
  */
 
 /*
@@ -135,7 +135,8 @@ portal_lookup(struct vop_lookup_args *ap)
        MALLOC(pt, struct portalnode *, sizeof(struct portalnode),
                M_TEMP, M_WAITOK);
 
-       error = getnewvnode(VT_PORTAL, dvp->v_mount, dvp->v_mount->mnt_vn_ops, &fvp);
+       error = getnewvnode(VT_PORTAL, dvp->v_mount, dvp->v_mount->mnt_vn_ops,
+                           &fvp, 0, 0);
        if (error) {
                FREE(pt, M_TEMP);
                goto bad;
index e00543b..afe0369 100644 (file)
@@ -37,7 +37,7 @@
  *     @(#)procfs_subr.c       8.6 (Berkeley) 5/14/95
  *
  * $FreeBSD: src/sys/miscfs/procfs/procfs_subr.c,v 1.26.2.3 2002/02/18 21:28:04 des Exp $
- * $DragonFly: src/sys/vfs/procfs/procfs_subr.c,v 1.9 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_subr.c,v 1.10 2004/08/28 19:02:27 dillon Exp $
  */
 
 #include <sys/param.h>
 
 #include <vfs/procfs/procfs.h>
 
-static struct pfsnode *pfshead;
+#define PFS_HSIZE      256
+#define PFS_HMASK      (PFS_HSIZE - 1)
+
+static struct pfsnode *pfshead[PFS_HSIZE];
 static int pfsvplock;
 
+#define PFSHASH(pid)   &pfshead[(pid) & PFS_HMASK]
+
 /*
- * allocate a pfsnode/vnode pair.  the vnode is
- * referenced, but not locked.
+ * Allocate a pfsnode/vnode pair.  If no error occurs the returned vnode
+ * will be referenced and exclusively locked.
  *
- * the pid, pfs_type, and mount point uniquely
- * identify a pfsnode.  the mount point is needed
- * because someone might mount this filesystem
+ * The pid, pfs_type, and mount point uniquely identify a pfsnode.
+ * The mount point is needed because someone might mount this filesystem
  * twice.
  *
- * all pfsnodes are maintained on a singly-linked
- * list.  new nodes are only allocated when they cannot
- * be found on this list.  entries on the list are
- * removed when the vfs reclaim entry is called.
+ * All pfsnodes are maintained on a singly-linked list.  new nodes are
+ * only allocated when they cannot be found on this list.  entries on
+ * the list are removed when the vfs reclaim entry is called.
  *
- * a single lock is kept for the entire list.  this is
- * needed because the getnewvnode() function can block
- * waiting for a vnode to become free, in which case there
- * may be more than one process trying to get the same
- * vnode.  this lock is only taken if we are going to
- * call getnewvnode, since the kernel itself is single-threaded.
+ * A single lock is kept for the entire list.  this is needed because the
+ * getnewvnode() function can block waiting for a vnode to become free,
+ * in which case there may be more than one process trying to get the same
+ * vnode.  this lock is only taken if we are going to call getnewvnode, 
+ * since the kernel itself is single-threaded.
  *
- * if an entry is found on the list, then call vget() to
- * take a reference.  this is done because there may be
- * zero references to it and so it needs to removed from
- * the vnode free list.
+ * If an entry is found on the list, then call vget() to take a reference
+ * and obtain the lock.  This will properly re-reference the vnode if it
+ * had gotten onto the free list.
  */
 int
 procfs_allocvp(struct mount *mp, struct vnode **vpp, long pid, pfstype pfs_type)
@@ -87,14 +88,34 @@ procfs_allocvp(struct mount *mp, struct vnode **vpp, long pid, pfstype pfs_type)
        struct vnode *vp;
        struct pfsnode **pp;
        int error;
+       lwkt_tokref vlock;
 
+       pp = PFSHASH(pid);
 loop:
-       for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) {
-               vp = PFSTOV(pfs);
-               if (pfs->pfs_pid == pid &&
-                   pfs->pfs_type == pfs_type &&
-                   vp->v_mount == mp) {
-                       if (vget(vp, NULL, 0, td))
+       for (pfs = *pp; pfs; pfs = pfs->pfs_next) {
+               if (pfs->pfs_pid == pid && pfs->pfs_type == pfs_type &&
+                   PFSTOV(pfs)->v_mount == mp) {
+                       vp = PFSTOV(pfs);
+                       lwkt_gettoken(&vlock, vp->v_interlock);
+
+                       /*
+                        * Make sure the vnode is still in the cache after
+                        * getting the interlock to avoid racing a free.
+                        */
+                       for (pfs = *pp; pfs; pfs = pfs->pfs_next) {
+                               if (PFSTOV(pfs) == vp &&
+                                   pfs->pfs_pid == pid && 
+                                   pfs->pfs_type == pfs_type &&
+                                   PFSTOV(pfs)->v_mount == mp) {
+                                       break;
+                               }
+                       }
+                       if (pfs == NULL) {
+                               lwkt_reltoken(&vlock);
+                               goto loop;
+
+                       }
+                       if (vget(vp, &vlock, LK_EXCLUSIVE | LK_INTERLOCK, td))
                                goto loop;
                        *vpp = vp;
                        return (0);
@@ -119,12 +140,16 @@ loop:
         */
        MALLOC(pfs, struct pfsnode *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
 
-       if ((error = getnewvnode(VT_PROCFS, mp, mp->mnt_vn_ops, vpp)) != 0) {
-               FREE(pfs, M_TEMP);
+       error = getnewvnode(VT_PROCFS, mp, mp->mnt_vn_ops, vpp, 0, 0);
+       if (error) {
+               free(pfs, M_TEMP);
                goto out;
        }
        vp = *vpp;
 
+       if (lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL, td))
+               panic("procfs_allocvp: unexpected lock vailure");
+
        vp->v_data = pfs;
 
        pfs->pfs_next = 0;
@@ -200,8 +225,7 @@ loop:
        }
 
        /* add to procfs vnode list */
-       for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next)
-               continue;
+       pfs->pfs_next = *pp;
        *pp = pfs;
 
 out:
@@ -219,17 +243,18 @@ int
 procfs_freevp(struct vnode *vp)
 {
        struct pfsnode **pfspp;
-       struct pfsnode *pfs = VTOPFS(vp);
+       struct pfsnode *pfs;
 
-       for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) {
-               if (*pfspp == pfs) {
-                       *pfspp = pfs->pfs_next;
-                       break;
-               }
-       }
+       pfs = VTOPFS(vp);
+       vp->v_data = NULL;
 
-       FREE(vp->v_data, M_TEMP);
-       vp->v_data = 0;
+       pfspp = PFSHASH(pfs->pfs_pid);
+       while (*pfspp != pfs && *pfspp)
+               pfspp = &(*pfspp)->pfs_next;
+       KKASSERT(*pfspp);
+       *pfspp = pfs->pfs_next;
+       pfs->pfs_next = NULL;
+       free(pfs, M_TEMP);
        return (0);
 }
 
@@ -397,12 +422,14 @@ procfs_exit(struct thread *td)
         * pfshead is skipped over.
         *
         */
-       pfs = pfshead;
+again:
+       pfs = *PFSHASH(pid);
        while (pfs) {
                if (pfs->pfs_pid == pid) {
                        vgone(PFSTOV(pfs));
-                       pfs = pfshead;
-               } else
-                       pfs = pfs->pfs_next;
+                       goto again;
+               }
+               pfs = pfs->pfs_next;
        }
 }
+
index b58c2f4..689733d 100644 (file)
@@ -37,7 +37,7 @@
  *     @(#)procfs_vfsops.c     8.7 (Berkeley) 5/10/95
  *
  * $FreeBSD: src/sys/miscfs/procfs/procfs_vfsops.c,v 1.32.2.1 2001/10/15 20:42:01 des Exp $
- * $DragonFly: src/sys/vfs/procfs/procfs_vfsops.c,v 1.7 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_vfsops.c,v 1.8 2004/08/28 19:02:27 dillon Exp $
  */
 
 /*
@@ -120,10 +120,12 @@ procfs_unmount(struct mount *mp, int mntflags, struct thread *td)
        return (0);
 }
 
+/*
+ * Sets *vpp to the root procfs vnode, referenced and exclusively locked.
+ */
 int
 procfs_root(struct mount *mp, struct vnode **vpp)
 {
-
        return (procfs_allocvp(mp, vpp, 0, Proot));
 }
 
index 99beafc..d862df6 100644 (file)
@@ -37,7 +37,7 @@
  *     @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
  *
  * $FreeBSD: src/sys/miscfs/procfs/procfs_vnops.c,v 1.76.2.7 2002/01/22 17:22:59 nectar Exp $
- * $DragonFly: src/sys/vfs/procfs/procfs_vnops.c,v 1.18 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_vnops.c,v 1.19 2004/08/28 19:02:27 dillon Exp $
  */
 
 /*
@@ -655,13 +655,8 @@ found:
 }
 
 /*
- * lookup.  this is incredibly complicated in the
- * general case, however for most pseudo-filesystems
- * very little needs to be done.
- *
- * unless you want to get a migraine, just make sure your
- * filesystem doesn't do any locking of its own.  otherwise
- * read and inwardly digest ufs_lookup().
+ * lookup.  this is incredibly complicated in the general case, however
+ * for most pseudo-filesystems very little needs to be done.
  *
  * procfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
  *              struct componentname *a_cnp)
@@ -679,17 +674,18 @@ procfs_lookup(struct vop_lookup_args *ap)
        struct pfsnode *pfs;
        struct proc *p;
        int i;
+       int error;
 
        *vpp = NULL;
 
        if (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)
                return (EROFS);
 
+       error = 0;
        if (cnp->cn_namelen == 1 && *pname == '.') {
                *vpp = dvp;
-               vref(dvp);
-               /* vn_lock(dvp, NULL, LK_EXCLUSIVE | LK_RETRY, curp); */
-               return (0);
+               vref(*vpp);
+               goto out;
        }
 
        pfs = VTOPFS(dvp);
@@ -698,8 +694,10 @@ procfs_lookup(struct vop_lookup_args *ap)
                if (cnp->cn_flags & CNP_ISDOTDOT)
                        return (EIO);
 
-               if (CNEQ(cnp, "curproc", 7))
-                       return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc));
+               if (CNEQ(cnp, "curproc", 7)) {
+                       error = procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc);
+                       goto out;
+               }
 
                pid = atopid(pname, cnp->cn_namelen);
                if (pid == NO_PID)
@@ -713,11 +711,14 @@ procfs_lookup(struct vop_lookup_args *ap)
                    ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
                        break;
 
-               return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc));
+               error = procfs_allocvp(dvp->v_mount, vpp, pid, Pproc);
+               goto out;
 
        case Pproc:
-               if (cnp->cn_flags & CNP_ISDOTDOT)
-                       return (procfs_root(dvp->v_mount, vpp));
+               if (cnp->cn_flags & CNP_ISDOTDOT) {
+                       error = procfs_root(dvp->v_mount, vpp);
+                       goto out;
+               }
 
                p = PFIND(pfs->pfs_pid);
                if (p == NULL)
@@ -735,14 +736,31 @@ procfs_lookup(struct vop_lookup_args *ap)
                }
                break;
        found:
-               return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
-                   pt->pt_pfstype));
+               error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
+                                       pt->pt_pfstype);
+               goto out;
 
        default:
-               return (ENOTDIR);
+               error = ENOTDIR;
+               goto out;
        }
-
-       return (cnp->cn_nameiop == NAMEI_LOOKUP ? ENOENT : EROFS);
+       if (cnp->cn_nameiop == NAMEI_LOOKUP)
+               error = ENOENT;
+       else
+               error = EROFS;
+       /*
+        * If no error occured *vpp will hold a referenced locked vnode.
+        * dvp was passed to us locked and *vpp must be returned locked
+        * so if dvp != *vpp and CNP_LOCKPARENT is not set, unlock dvp.
+        */
+out:
+       if (error == 0) {
+               if (*vpp != dvp && (cnp->cn_flags & CNP_LOCKPARENT) == 0) {
+                       cnp->cn_flags |= CNP_PDIRUNLOCK;
+                       VOP_UNLOCK(dvp, NULL, 0, cnp->cn_td);
+               }
+       }
+       return (error);
 }
 
 /*
index c8421c0..05ef73f 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/smbfs/smbfs_node.c,v 1.2.2.3 2003/01/17 08:20:26 tjr Exp $
- * $DragonFly: src/sys/vfs/smbfs/smbfs_node.c,v 1.12 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/smbfs/smbfs_node.c,v 1.13 2004/08/28 19:02:28 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -219,7 +219,8 @@ loop:
                return ENOENT;
 
        MALLOC(np, struct smbnode *, sizeof *np, M_SMBNODE, M_WAITOK);
-       error = getnewvnode(VT_SMBFS, mp, mp->mnt_vn_ops, &vp);
+       error = getnewvnode(VT_SMBFS, mp, mp->mnt_vn_ops, &vp,
+                           VLKTIMEOUT, LK_CANRECURSE);
        if (error) {
                FREE(np, M_SMBNODE);
                return error;
@@ -242,7 +243,6 @@ loop:
        } else if (vp->v_type == VREG)
                SMBERROR("new vnode '%s' born without parent ?\n", np->n_name);
 
-       lockinit(&np->n_lock, 0, "smbnode", VLKTIMEOUT, LK_CANRECURSE);
        vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
 
        smbfs_hash_lock(smp, td);
index bbd58ba..d1ffca2 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/smbfs/smbfs_node.h,v 1.1.2.2 2003/01/17 08:20:26 tjr Exp $
- * $DragonFly: src/sys/vfs/smbfs/smbfs_node.h,v 1.3 2004/05/03 16:06:26 joerg Exp $
+ * $DragonFly: src/sys/vfs/smbfs/smbfs_node.h,v 1.4 2004/08/28 19:02:28 dillon Exp $
  */
 #ifndef _FS_SMBFS_NODE_H_
 #define _FS_SMBFS_NODE_H_
@@ -49,7 +49,6 @@
 struct smbfs_fctx;
 
 struct smbnode {
-       struct lock             n_lock;         /* smbnode lock. (mbf) */
        int                     n_flag;
        struct vnode *          n_parent;
        struct vnode *          n_vnode;
index df0c4e2..667e758 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/smbfs/smbfs_vnops.c,v 1.2.2.8 2003/04/04 08:57:23 tjr Exp $
- * $DragonFly: src/sys/vfs/smbfs/smbfs_vnops.c,v 1.15 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/smbfs/smbfs_vnops.c,v 1.16 2004/08/28 19:02:28 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -793,7 +793,7 @@ smbfs_print(struct vop_print_args *ap)
        printf("tag VT_SMBFS, name = %s, parent = %p, opencount = %d",
            np->n_name, np->n_parent ? np->n_parent : NULL,
            np->n_opencount);
-       lockmgr_printinfo(&np->n_lock);
+       lockmgr_printinfo(&vp->v_lock);
        printf("\n");
        return (0);
 }
index 38ce212..9856bce 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/udf/udf_vnops.c,v 1.33 2003/12/07 05:04:49 scottl Exp $
- * $DragonFly: src/sys/vfs/udf/udf_vnops.c,v 1.6 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/udf/udf_vnops.c,v 1.7 2004/08/28 19:02:29 dillon Exp $
  */
 
 /* udf_vnops.c */
@@ -111,9 +111,10 @@ loop:
                 * out from under us after blocking.
                 */
                lh = &udfmp->hashtbl[id % udfmp->hashsz];
-               LIST_FOREACH(node, lh, le)
+               LIST_FOREACH(node, lh, le) {
                        if (node->hash_id == id)
                                break;
+               }
                if (node == NULL) {
                        lwkt_reltoken(&vlock);
                        goto loop;
@@ -178,7 +179,7 @@ udf_allocv(struct mount *mp, struct vnode **vpp)
        int error;
        struct vnode *vp;
 
-       error = getnewvnode(VT_UDF, mp, mp->mnt_vn_ops, &vp);
+       error = getnewvnode(VT_UDF, mp, mp->mnt_vn_ops, &vp, 0, 0);
        if (error) {
                printf("udf_allocv: failed to allocate new vnode\n");
                return(error);
index 2ca7b8c..1b99a8f 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)ffs_vfsops.c        8.31 (Berkeley) 5/20/95
  * $FreeBSD: src/sys/ufs/ffs/ffs_vfsops.c,v 1.117.2.10 2002/06/23 22:34:52 iedowse Exp $
- * $DragonFly: src/sys/vfs/ufs/ffs_vfsops.c,v 1.23 2004/08/24 14:01:57 drhodus Exp $
+ * $DragonFly: src/sys/vfs/ufs/ffs_vfsops.c,v 1.24 2004/08/28 19:02:30 dillon Exp $
  */
 
 #include "opt_quota.h"
@@ -529,8 +529,8 @@ ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td)
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
                        size = (blks - i) * fs->fs_fsize;
-               if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
-                   &bp)) {
+               error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, &bp);
+               if (error) {
                        brelse(bp);
                        return (error);
                }
@@ -1116,7 +1116,6 @@ ffs_sync_scan2(struct mount *mp, struct vnode *vp,
  * return the inode locked.  Detection and handling of mount points must be
  * done by the calling routine.
  */
-static int ffs_inode_hash_lock;
 
 int
 ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
@@ -1136,20 +1135,6 @@ restart:
                return (0);
        }
 
-       /*
-        * Lock out the creation of new entries in the FFS hash table in
-        * case getnewvnode() or MALLOC() blocks, otherwise a duplicate
-        * may occur!
-        */
-       if (ffs_inode_hash_lock) {
-               while (ffs_inode_hash_lock) {
-                       ffs_inode_hash_lock = -1;
-                       tsleep(&ffs_inode_hash_lock, 0, "ffsvgt", 0);
-               }
-               goto restart;
-       }
-       ffs_inode_hash_lock = 1;
-
        /*
         * If this MALLOC() is performed after the getnewvnode()
         * it might block, leaving a vnode with a NULL v_data to be
@@ -1161,22 +1146,15 @@ restart:
            ump->um_malloctype, M_WAITOK);
 
        /* Allocate a new vnode/inode. */
-       error = getnewvnode(VT_UFS, mp, mp->mnt_vn_ops, &vp);
+       error = getnewvnode(VT_UFS, mp, mp->mnt_vn_ops, &vp,
+                           VLKTIMEOUT, LK_CANRECURSE);
        if (error) {
-               if (ffs_inode_hash_lock < 0)
-                       wakeup(&ffs_inode_hash_lock);
-               ffs_inode_hash_lock = 0;
                *vpp = NULL;
-               FREE(ip, ump->um_malloctype);
+               free(ip, ump->um_malloctype);
                return (error);
        }
        bzero((caddr_t)ip, sizeof(struct inode));
-       lockinit(&ip->i_lock, 0, "inode", VLKTIMEOUT, LK_CANRECURSE);
-       vp->v_data = ip;
-       /*
-        * FFS supports lock sharing in the stack of vnodes
-        */
-       vp->v_vnlock = &ip->i_lock;
+       lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL, curthread);
        ip->i_vnode = vp;
        ip->i_fs = fs = ump->um_fs;
        ip->i_dev = dev;
@@ -1190,16 +1168,17 @@ restart:
 #endif
 
        /*
-        * Put it onto its hash chain and lock it so that other requests for
-        * this inode will block if they arrive while we are sleeping waiting
-        * for old data structures to be purged or for the contents of the
-        * disk portion of this inode to be read.
+        * Insert it into the inode hash table and check for a collision.
+        * If a collision occurs, throw away the vnode and try again.
         */
-       ufs_ihashins(ip);
-
-       if (ffs_inode_hash_lock < 0)
-               wakeup(&ffs_inode_hash_lock);
-       ffs_inode_hash_lock = 0;
+       if (ufs_ihashins(ip) != 0) {
+               printf("debug: ufs ihashins collision, retrying inode %ld\n",
+                   (long)ip->i_number);
+               vput(vp);
+               free(ip, ump->um_malloctype);
+               goto restart;
+       }
+       vp->v_data = ip;
 
        /* Read in the disk contents for the inode, copy into the inode. */
        error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
index b2407e4..e2b7013 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)inode.h     8.9 (Berkeley) 5/14/95
  * $FreeBSD: src/sys/ufs/ufs/inode.h,v 1.28.2.2 2001/09/29 12:52:52 iedowse Exp $
- * $DragonFly: src/sys/vfs/ufs/inode.h,v 1.7 2004/07/18 19:43:48 drhodus Exp $
+ * $DragonFly: src/sys/vfs/ufs/inode.h,v 1.8 2004/08/28 19:02:30 dillon Exp $
  */
 
 #ifndef _UFS_UFS_INODE_H_
@@ -76,8 +76,7 @@ typedef long ufs_lbn_t;
  * active, and is put back when the file is no longer being used.
  */
 struct inode {
-       struct   lock i_lock;   /* Inode lock. >Keep this first< */
-       LIST_ENTRY(inode) i_hash;/* Hash chain. */
+       struct inode    *i_next;/* Hash chain */
        struct  vnode  *i_vnode;/* Vnode associated with this inode. */
        struct  vnode  *i_devvp;/* Vnode for block I/O. */
        uint32_t i_flag;        /* flags, see below */
index 552517c..5a95436 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)ufs_extern.h        8.10 (Berkeley) 5/14/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_extern.h,v 1.27.2.1 2000/12/28 11:01:46 ps Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_extern.h,v 1.8 2004/08/17 18:57:36 dillon Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_extern.h,v 1.9 2004/08/28 19:02:30 dillon Exp $
  */
 
 #ifndef _UFS_UFS_EXTERN_H_
@@ -79,7 +79,7 @@ int    ufs_getlbns(struct vnode *, ufs_daddr_t, struct indir *, int *);
 struct vnode *
         ufs_ihashget(dev_t, ino_t);
 void    ufs_ihashinit(void);
-void    ufs_ihashins(struct inode *);
+int     ufs_ihashins(struct inode *);
 struct vnode *
         ufs_ihashlookup(dev_t, ino_t);
 void    ufs_ihashrem(struct inode *);
index 2e6fa44..bb6d97b 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_ihash.c,v 1.20 1999/08/28 00:52:29 peter Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_ihash.c,v 1.12 2004/05/18 00:16:46 cpressey Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_ihash.c,v 1.13 2004/08/28 19:02:30 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -51,18 +51,23 @@ static MALLOC_DEFINE(M_UFSIHASH, "UFS ihash", "UFS Inode hash tables");
 /*
  * Structures associated with inode cacheing.
  */
-static LIST_HEAD(ihashhead, inode) *ihashtbl;
+static struct inode **ihashtbl;
 static u_long  ihash;          /* size of hash table - 1 */
-#define        INOHASH(device, inum)   (&ihashtbl[(minor(device) + (inum)) & ihash])
 static struct lwkt_token ufs_ihash_token;
 
+#define        INOHASH(device, inum)   (&ihashtbl[(minor(device) + (inum)) & ihash])
+
 /*
  * Initialize inode hash table.
  */
 void
 ufs_ihashinit(void)
 {
-       ihashtbl = hashinit(desiredvnodes, M_UFSIHASH, &ihash);
+       ihash = 16;
+       while (ihash < desiredvnodes)
+               ihash <<= 1;
+       ihashtbl = malloc(sizeof(void *) * ihash, M_UFSIHASH, M_WAITOK|M_ZERO);
+       --ihash;
        lwkt_token_init(&ufs_ihash_token);
 }
 
@@ -77,12 +82,11 @@ ufs_ihashlookup(dev_t dev, ino_t inum)
        lwkt_tokref ilock;
 
        lwkt_gettoken(&ilock, &ufs_ihash_token);
-       for (ip = INOHASH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) {
+       for (ip = *INOHASH(dev, inum); ip; ip = ip->i_next) {
                if (inum == ip->i_number && dev == ip->i_dev)
                        break;
        }
        lwkt_reltoken(&ilock);
-
        if (ip)
                return (ITOV(ip));
        return (NULLVP);
@@ -108,7 +112,7 @@ ufs_ihashget(dev_t dev, ino_t inum)
 
        lwkt_gettoken(&ilock, &ufs_ihash_token);
 loop:
-       for (ip = INOHASH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) {
+       for (ip = *INOHASH(dev, inum); ip; ip = ip->i_next) {
                if (inum != ip->i_number || dev != ip->i_dev)
                        continue;
                vp = ITOV(ip);
@@ -117,7 +121,7 @@ loop:
                 * We must check to see if the inode has been ripped
                 * out from under us after blocking.
                 */
-               for (ip = INOHASH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) {
+               for (ip = *INOHASH(dev, inum); ip; ip = ip->i_next) {
                        if (inum == ip->i_number && dev == ip->i_dev)
                                break;
                }
@@ -137,21 +141,28 @@ loop:
 /*
  * Insert the inode into the hash table, and return it locked.
  */
-void
+int
 ufs_ihashins(struct inode *ip)
 {
-       struct thread *td = curthread;          /* XXX */
-       struct ihashhead *ipp;
+       struct inode **ipp;
+       struct inode *iq;
        lwkt_tokref ilock;
 
-       /* lock the inode, then put it on the appropriate hash list */
-       lockmgr(&ip->i_lock, LK_EXCLUSIVE, NULL, td);
-
+       KKASSERT((ip->i_flag & IN_HASHED) == 0);
        lwkt_gettoken(&ilock, &ufs_ihash_token);
        ipp = INOHASH(ip->i_dev, ip->i_number);
-       LIST_INSERT_HEAD(ipp, ip, i_hash);
+       while ((iq = *ipp) != NULL) {
+               if (ip->i_dev == iq->i_dev && ip->i_number == iq->i_number) {
+                       lwkt_reltoken(&ilock);
+                       return(EBUSY);
+               }
+               ipp = &iq->i_next;
+       }
+       ip->i_next = NULL;
+       *ipp = ip;
        ip->i_flag |= IN_HASHED;
        lwkt_reltoken(&ilock);
+       return(0);
 }
 
 /*
@@ -161,15 +172,22 @@ void
 ufs_ihashrem(struct inode *ip)
 {
        lwkt_tokref ilock;
+       struct inode **ipp;
+       struct inode *iq;
 
        lwkt_gettoken(&ilock, &ufs_ihash_token);
        if (ip->i_flag & IN_HASHED) {
+               ipp = INOHASH(ip->i_dev, ip->i_number);
+               while ((iq = *ipp) != NULL) {
+                       if (ip == iq)
+                               break;
+                       ipp = &iq->i_next;
+               }
+               KKASSERT(ip == iq);
+               *ipp = ip->i_next;
+               ip->i_next = NULL;
                ip->i_flag &= ~IN_HASHED;
-               LIST_REMOVE(ip, i_hash);
-#ifdef DIAGNOSTIC
-               ip->i_hash.le_next = NULL;
-               ip->i_hash.le_prev = NULL;
-#endif
        }
        lwkt_reltoken(&ilock);
 }
+
index bf2ae87..3dfb43b 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)ufs_inode.c 8.9 (Berkeley) 5/14/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_inode.c,v 1.25.2.3 2002/07/05 22:42:31 dillon Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_inode.c,v 1.8 2004/05/18 00:16:46 cpressey Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_inode.c,v 1.9 2004/08/28 19:02:30 dillon Exp $
  */
 
 #include "opt_quota.h"
@@ -78,7 +78,7 @@ ufs_inactive(struct vop_inactive_args *ap)
        /*
         * Ignore inodes related to stale file handles.
         */
-       if (ip->i_mode == 0)
+       if (ip == NULL || ip->i_mode == 0)
                goto out;
        if (ip->i_nlink <= 0) {
 #ifdef QUOTA
@@ -100,7 +100,7 @@ out:
         * If we are done with the inode, reclaim it
         * so that it can be reused immediately.
         */
-       if (ip->i_mode == 0)
+       if (ip == NULL || ip->i_mode == 0)
                vrecycle(vp, NULL, td);
        return (error);
 }
@@ -122,35 +122,35 @@ ufs_reclaim(struct vop_reclaim_args *ap)
        if (prtactive && vp->v_usecount != 0)
                vprint("ufs_reclaim: pushing active", vp);
        ip = VTOI(vp);
-       if (ip->i_flag & IN_LAZYMOD) {
+       if (ip && (ip->i_flag & IN_LAZYMOD)) {
                ip->i_flag |= IN_MODIFIED;
                UFS_UPDATE(vp, 0);
        }
        /*
-        * Remove the inode from its hash chain.
-        */
-       ufs_ihashrem(ip);
-       /*
-        * Purge old data structures associated with the inode.
+        * Remove the inode from its hash chain and purge namecache
+        * data associated with the vnode.
         */
        cache_purge(vp);
-       if (ip->i_devvp) {
-               vrele(ip->i_devvp);
-               ip->i_devvp = 0;
-       }
+       vp->v_data = NULL;
+       if (ip) {
+               ufs_ihashrem(ip);
+               if (ip->i_devvp) {
+                       vrele(ip->i_devvp);
+                       ip->i_devvp = 0;
+               }
 #ifdef QUOTA
-       for (i = 0; i < MAXQUOTAS; i++) {
-               if (ip->i_dquot[i] != NODQUOT) {
-                       dqrele(vp, ip->i_dquot[i]);
-                       ip->i_dquot[i] = NODQUOT;
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       if (ip->i_dquot[i] != NODQUOT) {
+                               dqrele(vp, ip->i_dquot[i]);
+                               ip->i_dquot[i] = NODQUOT;
+                       }
                }
-       }
 #endif
 #ifdef UFS_DIRHASH
-       if (ip->i_dirhash != NULL)
-               ufsdirhash_free(ip);
+               if (ip->i_dirhash != NULL)
+                       ufsdirhash_free(ip);
 #endif
-       FREE(vp->v_data, VFSTOUFS(vp->v_mount)->um_malloctype);
-       vp->v_data = 0;
+               free(ip, VFSTOUFS(vp->v_mount)->um_malloctype);
+       }
        return (0);
 }
index 6d22c17..10b69db 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_vnops.c,v 1.131.2.8 2003/01/02 17:26:19 bde Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_vnops.c,v 1.19 2004/08/25 00:05:11 dillon Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_vnops.c,v 1.20 2004/08/28 19:02:30 dillon Exp $
  */
 
 #include "opt_quota.h"
@@ -1739,7 +1739,7 @@ ufs_print(struct vop_print_args *ap)
            minor(ip->i_dev));
        if (vp->v_type == VFIFO)
                fifo_printinfo(vp);
-       lockmgr_printinfo(&ip->i_lock);
+       lockmgr_printinfo(&vp->v_lock);
        printf("\n");
        return (0);
 }
index a5cd8ae..af77625 100644 (file)
  *     @(#)umap.h      8.4 (Berkeley) 8/20/94
  *
  * $FreeBSD: src/sys/miscfs/umapfs/umap.h,v 1.13 1999/12/29 04:54:47 peter Exp $
- * $DragonFly: src/sys/vfs/umapfs/Attic/umap.h,v 1.6 2004/08/17 18:57:36 dillon Exp $
+ * $DragonFly: src/sys/vfs/umapfs/Attic/umap.h,v 1.7 2004/08/28 19:02:31 dillon Exp $
  */
 
+#include <vfs/nullfs/null.h>
+
 #define MAPFILEENTRIES 64
 #define GMAPFILEENTRIES 16
 #define NOBODY 32767
@@ -68,15 +70,18 @@ struct umap_mount {
  * A cache of vnode references
  */
 struct umap_node {
-       LIST_ENTRY(umap_node) umap_hash;        /* Hash list */
-       struct vnode    *umap_lowervp;  /* Aliased vnode - vref'ed once */
-       struct vnode    *umap_vnode;    /* Back pointer to vnode/umap_node */
+       struct null_node        umap_null;
 };
 
+#define umap_next      umap_null.null_next
+#define umap_lowervp   umap_null.null_lowervp
+#define umap_vnode     umap_null.null_vnode
+
 extern int umapfs_init (struct vfsconf *vfsp);
 extern int umap_node_create (struct mount *mp, struct vnode *target, struct vnode **vpp);
 extern u_long umap_reverse_findid (u_long id, u_long map[][2], int nentries);
 extern void umap_mapids (struct mount *v_mount, struct ucred *credp);
+extern void umap_node_delete(struct umap_node *xp);
 
 #define        MOUNTTOUMAPMOUNT(mp) ((struct umap_mount *)((mp)->mnt_data))
 #define        VTOUMAP(vp) ((struct umap_node *)(vp)->v_data)
index c6294cd..b71ebf4 100644 (file)
@@ -36,7 +36,7 @@
  *     @(#)umap_subr.c 8.9 (Berkeley) 5/14/95
  *
  * $FreeBSD: src/sys/miscfs/umapfs/umap_subr.c,v 1.19 1999/09/04 11:51:41 bde Exp $
- * $DragonFly: src/sys/vfs/umapfs/Attic/umap_subr.c,v 1.10 2004/08/17 18:57:36 dillon Exp $
+ * $DragonFly: src/sys/vfs/umapfs/Attic/umap_subr.c,v 1.11 2004/08/28 19:02:31 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -48,7 +48,6 @@
 #include "umap.h"
 
 #define LOG2_SIZEVNODE 7               /* log2(sizeof struct vnode) */
-#define        NUMAPNODECACHE 16
 
 /*
  * Null layer cache:
@@ -61,7 +60,7 @@
 #define        UMAP_NHASH(vp) \
        (&umap_node_hashtbl \
        [((uintptr_t)(void *)(vp) >> LOG2_SIZEVNODE) & umap_node_hash])
-static LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl;
+static struct umap_node **umap_node_hashtbl;
 static u_long umap_node_hash;
 
 static u_long  umap_findid (u_long id, u_long map[][2], int nentries);
@@ -79,7 +78,12 @@ umapfs_init(struct vfsconf *vfsp)
 #ifdef DEBUG
        printf("umapfs_init\n");                /* printed during system boot */
 #endif
-       umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash);
+       umap_node_hash = 16;
+       while (umap_node_hash < desiredvnodes)
+               umap_node_hash <<= 1;
+       umap_node_hashtbl = malloc(sizeof(void *) * umap_node_hash, M_CACHE,
+                                  M_WAITOK|M_ZERO);
+       --umap_node_hash;
        return (0);
 }
 
@@ -130,8 +134,8 @@ static struct vnode *
 umap_node_find(struct mount *mp, struct vnode *targetvp)
 {
        struct thread *td = curthread;          /* XXX */
-       struct umap_node_hashhead *hd;
-       struct umap_node *a;
+       struct umap_node **xpp;
+       struct umap_node *xp;
        struct vnode *vp;
 
 #ifdef DEBUG
@@ -145,12 +149,12 @@ umap_node_find(struct mount *mp, struct vnode *targetvp)
         * the target vnode.  If found, the increment the umap_node
         * reference count (but NOT the target vnode's vref counter).
         */
-       hd = UMAP_NHASH(targetvp);
+       xpp = UMAP_NHASH(targetvp);
 loop:
-       for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) {
-               if (a->umap_lowervp == targetvp &&
-                   a->umap_vnode->v_mount == mp) {
-                       vp = UMAPTOV(a);
+       for (xp = *xpp; xp; xp = (void *)xp->umap_next) {
+               if (xp->umap_lowervp == targetvp &&
+                   xp->umap_vnode->v_mount == mp) {
+                       vp = UMAPTOV(xp);
                        /*
                         * We need vget for the VXLOCK
                         * stuff, but we don't want to lock
@@ -182,8 +186,8 @@ loop:
 static int
 umap_node_alloc(struct mount *mp, struct vnode *lowervp, struct vnode **vpp)
 {
-       struct umap_node_hashhead *hd;
        struct umap_node *xp;
+       struct umap_node **xpp;
        struct vnode *othervp, *vp;
        int error;
 
@@ -197,7 +201,7 @@ umap_node_alloc(struct mount *mp, struct vnode *lowervp, struct vnode **vpp)
        MALLOC(xp, struct umap_node *, sizeof(struct umap_node),
            M_TEMP, M_WAITOK);
 
-       error = getnewvnode(VT_UMAP, mp, mp->mnt_vn_ops, vpp);
+       error = getnewvnode(VT_UMAP, mp, mp->mnt_vn_ops, vpp, 0, 0);
        if (error) {
                FREE(xp, M_TEMP);
                return (error);
@@ -222,11 +226,24 @@ umap_node_alloc(struct mount *mp, struct vnode *lowervp, struct vnode **vpp)
                return (0);
        }
        vref(lowervp);   /* Extra vref will be vrele'd in umap_node_create */
-       hd = UMAP_NHASH(lowervp);
-       LIST_INSERT_HEAD(hd, xp, umap_hash);
+       xpp = UMAP_NHASH(lowervp);
+       xp->umap_next = (void *)*xpp;
+       *xpp = xp;
        return (0);
 }
 
+void
+umap_node_delete(struct umap_node *xp)
+{
+       struct umap_node **xpp;
+
+       xpp = UMAP_NHASH(xp->umap_lowervp);
+       while (*xpp && *xpp != xp)
+               xpp = &(*xpp)->umap_next;
+       KKASSERT(*xpp);
+       *xpp = (void *)xp->umap_next;
+       xp->umap_next = NULL;
+}
 
 /*
  * Try to find an existing umap_node vnode refering
index ff25b7c..1140a4a 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)umap_vnops.c        8.6 (Berkeley) 5/22/95
  * $FreeBSD: src/sys/miscfs/umapfs/umap_vnops.c,v 1.30 1999/08/30 07:08:04 bde Exp $
- * $DragonFly: src/sys/vfs/umapfs/Attic/umap_vnops.c,v 1.10 2004/08/17 18:57:36 dillon Exp $
+ * $DragonFly: src/sys/vfs/umapfs/Attic/umap_vnops.c,v 1.11 2004/08/28 19:02:31 dillon Exp $
  */
 
 /*
@@ -53,7 +53,6 @@
 #include <sys/malloc.h>
 #include <sys/buf.h>
 #include "umap.h"
-#include <vfs/nullfs/null.h>
 
 static int umap_bug_bypass = 0;   /* for debugging: enables bypass printf'ing */
 SYSCTL_INT(_debug, OID_AUTO, umapfs_bug_bypass, CTLFLAG_RW,
@@ -357,10 +356,12 @@ umap_getattr(struct vop_getattr_args *ap)
 static int
 umap_lock(struct vop_lock_args *ap)
 {
-       vop_nolock(ap);
+       if (ap->a_flags & LK_INTERLOCK) {
+               lwkt_reltoken(ap->a_vlock);
+               ap->a_flags &= ~LK_INTERLOCK;
+       }
        if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
                return (0);
-       ap->a_flags &= ~LK_INTERLOCK;
        return (null_bypass(&ap->a_head));
 }
 
@@ -374,8 +375,10 @@ umap_lock(struct vop_lock_args *ap)
 int
 umap_unlock(struct vop_unlock_args *ap)
 {
-       vop_nounlock(ap);
-       ap->a_flags &= ~LK_INTERLOCK;
+       if (ap->a_flags & LK_INTERLOCK) {
+               lwkt_reltoken(ap->a_vlock);
+               ap->a_flags &= ~LK_INTERLOCK;
+       }
        return (null_bypass(&ap->a_head));
 }
 
@@ -411,10 +414,10 @@ umap_reclaim(struct vop_reclaim_args *ap)
        struct vnode *lowervp = xp->umap_lowervp;
 
        /* After this assignment, this node will not be re-used. */
-       xp->umap_lowervp = NULL;
-       LIST_REMOVE(xp, umap_hash);
-       FREE(vp->v_data, M_TEMP);
        vp->v_data = NULL;
+       umap_node_delete(xp);
+       xp->umap_lowervp = NULL;
+       free(xp, M_TEMP);
        vrele(lowervp);
        return (0);
 }
index fd58764..4aea225 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     @(#)union_subr.c        8.20 (Berkeley) 5/20/95
  * $FreeBSD: src/sys/miscfs/union/union_subr.c,v 1.43.2.2 2001/12/25 01:44:45 dillon Exp $
- * $DragonFly: src/sys/vfs/union/union_subr.c,v 1.14 2004/08/17 18:57:36 dillon Exp $
+ * $DragonFly: src/sys/vfs/union/union_subr.c,v 1.15 2004/08/28 19:02:33 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -528,7 +528,7 @@ loop:
         * Create new node rather then replace old node
         */
 
-       error = getnewvnode(VT_UNION, mp, mp->mnt_vn_ops, vpp);
+       error = getnewvnode(VT_UNION, mp, mp->mnt_vn_ops, vpp, 0, 0);
        if (error) {
                /*
                 * If an error occurs clear out vnodes.
@@ -596,11 +596,11 @@ union_freevp(struct vnode *vp)
 {
        struct union_node *un = VTOUNION(vp);
 
+       vp->v_data = NULL;
        if (un->un_flags & UN_CACHED) {
                un->un_flags &= ~UN_CACHED;
                LIST_REMOVE(un, un_cache);
        }
-
        if (un->un_pvp != NULLVP) {
                vrele(un->un_pvp);
                un->un_pvp = NULL;
@@ -621,10 +621,7 @@ union_freevp(struct vnode *vp)
                free(un->un_path, M_TEMP);
                un->un_path = NULL;
        }
-
-       FREE(vp->v_data, M_TEMP);
-       vp->v_data = 0;
-
+       free(un, M_TEMP);
        return (0);
 }
 
index f89f178..737e462 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)vm_swap.c   8.5 (Berkeley) 2/17/94
  * $FreeBSD: src/sys/vm/vm_swap.c,v 1.96.2.2 2001/10/14 18:46:47 iedowse Exp $
- * $DragonFly: src/sys/vm/vm_swap.c,v 1.13 2004/08/13 17:51:14 dillon Exp $
+ * $DragonFly: src/sys/vm/vm_swap.c,v 1.14 2004/08/28 19:02:35 dillon Exp $
  */
 
 #include "opt_swap.h"
@@ -248,7 +248,7 @@ swaponvp(struct thread *td, struct vnode *vp, u_long nblks)
 
        if (!swapdev_vp) {
                error = getnewvnode(VT_NON, NULL, swapdev_vnode_vops,
-                   &swapdev_vp);
+                                   &swapdev_vp, 0, 0);
                if (error)
                        panic("Cannot get vnode for swapdev");
                swapdev_vp->v_type = VNON;      /* Untyped */